NOIP2014 解题报告·水渣记
Day 1:
第一次参加noip。小激动,小紧张,这些正常的情绪就不用说了。唯一值得一提的是 我早上步行去郑大工学院的时候迷路了,直接转进了隔壁的河南农大,绕了半天找不到机房,还给几个同学打了电话可就是没人接……于是就在保安异样的目光下灰溜溜地走出了校门= =...然后还算好,总算提前半个小时来到了考点。。。
然后找座位的时候我遇到了奇怪的事情!!我的座位旁边是夏五岳……同校+同语言……天知道负责人的随机数生成器是出了什么问题= =不过看起来我们似乎没有被监考的志愿者盯上?那就这样吧= =于是,按照平时的习惯,我先敲好了头文件和快速读入……(别问我为什么还有快速读入……我只是懒得每次打scanf又怕cin被卡……)然后……看题……
A: 生活大爆炸版石头剪刀布
给出五种手势的胜负关系,A、B的出拳循环节和总共进行的轮数N,求游戏结束时两人各自的输赢次数。
N <= 200。N <= 200。N <= 200。N <= 200。
QAQ……请告诉我我没有看错数据范围。请告诉我200遍我没有看错数据范围。不对……我是不是走错考场考成普及组了?可是普及组不应该是下午比赛吗……好吧好吧,我再检查200遍题目就开始敲代码。。。
于是开考后三十分钟,我开始了无脑模拟。话说这题要是数据范围再大那么几个零是不是就可以变成数论题了?= = 看来出题人有着特别的送分技巧……就这么敲完了模拟。果断开下一题?算了还是再检查200遍题目吧……万一理解错了呢……
2 /*======================BY ASM.DEF========================*/
3 /*========================================================*/
4 #include <cstdio>
5 #include <cctype>
6 #include <cstring>
7 #include <cmath>
8 #include <algorithm>
9 #include <vector>
#include <queue>
#if defined DEBUG
FILE *in = fopen("test", "r");
#define out stdout
#else
FILE *in = fopen("rps.in", "r");
FILE *out = fopen("rps.out", "w");
#endif
template<typename T> inline bool getd(T &x){
int c = fgetc(in);
;
while(c != '-' && c != EOF && !isdigit(c))c = fgetc(in);
;
if(c == '-'){
minus = ;
x = ;
}
';
+ c - ';
if(minus)x = -x;
;
}
using namespace std;
/*==========================================================*/
+ ;
][] = {{,,,,},{,,,,},{,,,,},{,,,,},{,,,,}};
int N, NA, NB;
, ansB = ;
int main(){
getd(N), getd(NA), getd(NB);
int i, a, b;
;i < NA;++i)
getd(A[i]);
;i < NB;++i)
getd(B[i]);
;i < N;++i){
a = A[i % NA];
b = B[i % NB];
if(win[a][b])++ansA;
if(win[b][a])++ansB;
}
fprintf(out, "%d %d\n", ansA, ansB);
;
}
无脑模拟
然后开始了第二题:
B:联合权值
$无向联通图G有n个节点,n-1条边。点从1~n依次编号,编号为i的点权值为W_i,每条边长度均为1.$
$图上两点u,v的距离定义为u,v的最短距离。$
$对于图上的点对(u,v),若它们的距离为2,则它们之间会产生W_u \times W_v的联合权值。$
$ 请问图上可能产生联合权值的有序点对中,联合权值最大的是多少?所有权值之和是多少?$
$n \leq 200000$
好吧我终于敢确定自己没有报成普及组了……
首先看到无向连通图和n-1条边,可知这是一棵树……(可是您把这两条信息都放在开头和直接说这是一棵树的区别在哪里QAQ)
然后很容易就会想到用树分治的方法统计。于是dfs一下,讨论一下兄弟节点和祖孙节点就可……等等。。。没有那么麻烦!我可以直接枚举中点!
因为要求的是树上距离为2的点对,根据树上路径的存在性&唯一性,可知它们有且只有一个公共的邻接点。于是我们可以直接把这个中点拎出来,这时很容易看出它的所有邻接点两两之间都可以产生“联合权值”。那么我们求的所有权值之和就是$$\sum\limits_{i=1}^N(\sum\limits_{u,v \in adj_i, u \neq v} W_u \times W_v)$$
但是每个节点的所有邻接点“两两之间的乘积之和”怎么求呢……对于任意一个中点i,我们可以把表达式写成这样:$$S_i = \sum_{j \in adj_i} (W_j \times (\sum_{k \in adj_i} W_k) - W_j)$$ 然后合并同类项,就成了$$S_i ={ (\sum_{j \in adj_i} W_j)} ^ 2 - \sum_{j \in adj_i} W_j^2$$。这样对于每个中点i的处理就只需$O(|adj_i|)$的时间,而每条边只处在两个节点的邻接表中,因此总时间复杂度为$O(n)$。
然后……为什么数据是个$O(nlogn)$级别的规模呢……表示不解。。。难道我证错了?
2 /*======================BY ASM.DEF========================*/
3 /*========================================================*/
4 #include <cstdio>
5 #include <iostream>
6 #include <cctype>
7 #include <cstring>
8 #include <cmath>
9 #include <algorithm>
#include <vector>
#include <queue>
#if defined DEBUG
FILE *in = fopen("test", "r");
#define out stdout
#else
FILE *in = fopen("linkb.in", "r");
FILE *out = fopen("linkb.out", "w");
#endif
#define pb push_back
#define iter(v) v::iterator
template<typename T> inline bool getd(T &x){
int c = fgetc(in);
;
while(c != '-' && c != EOF && !isdigit(c))c = fgetc(in);
;
if(c == '-'){
minus = ;
x = ;
}
';
+ c - ';
if(minus)x = -x;
;
}
using namespace std;
/*==========================================================*/
+ , mod = ;
}, Max = , Sum = ;
vector<int> adj[maxn];
inline bool cmp(int a, int b){return W[a] > W[b];}
inline void calc(int cur){
iter(vector<int>) it;
, wS = ;//平方和,权值和(\sum_{i=1}^{N}(a_i (\sum_{j=1}^N}a_j - a_i)) = wS^2 - pow2S)
, secmax = ;
for(it = adj[cur].begin();it != adj[cur].end();++it){
pow2S = (pow2S + W[*it] * W[*it]) % mod;
wS = (wS + W[*it]) % mod;
if(W[*it] > firmax)secmax = firmax, firmax = W[*it];
else if(W[*it] > secmax)secmax = W[*it];
}
Max = max(Max, firmax * secmax);
Sum = (Sum + wS * wS) % mod;
Sum = (Sum + mod - pow2S) % mod;
}
inline void work(){
int i, u, v;
getd(n);
;i < n;++i){
getd(u), getd(v);
adj[u].pb(v);
adj[v].pb(u);
}
;i <= n;++i)getd(W[i]);
;i <= n;++i)
calc(i);
fprintf(out, "%d %d\n", Max, Sum);
}
int main(){
work();
#if defined DEBUG
cout << endl << (double)clock() / CLOCKS_PER_SEC << " sec" << endl;
#endif
;
}
找公式
再然后……第三题改天再和day2一起写吧 ……反正我只写了70分算法= =
好了一周已经过去了......前几天发现我第二天太作死没有分试题建立文件夹,结果第二天的分数直接全0……据说按照我直接交上去的那份代码计算,这次还是可以拿到HA rank3的……这样一来,就相当于省rank3 -> 省三了= =真是醉……
我们再来看day1的第三题:
C:飞扬的小鸟
简化一下Flappy Bird, 在每个位置可以跳多次,跳一次上升$a_i$,如果不跳就下降$b_i$,问至少点击多少次能完成游戏(如果完成不了就输出最多能穿过多少缝隙)。
很容易发现这道题的动态规划性质,然后可以更容易地敲出$O(\frac{nm^2}{a_i})$的算法= =然后发现最后三个测试点有可能会超时……因为我在做状态转移的时候对每一个位置都枚举了所有可能到达的上一位置,所以这个复杂度其实是依赖输入的……如果所有的$a_i$都很大,那么这个算法也可以很快求出结果,但如果出题人爱玩codeforces(神脑补),将所有$a_i$都设为1,那我就必然超时了……
好吧说了那么多,说白了还是我太弱。。。结束之后发现这题的转移中的“允许跳多次”其实可以转化为完全背包模型……或者说,在所有高度中“模$a_i$等价类”中的元素的“跳跃次数”是单调递增的= =
然后……这个完全背包的解法我懒得写了= =不过对于山寨版本的随机数据,我的写法跑得还是很快的>_<
2 /*======================BY ASM.DEF========================*/
3 /*========================================================*/
4 #include <cstdio>
5 #include <iostream>
6 #include <cctype>
7 #include <cstring>
8 #include <cmath>
9 #include <algorithm>
10 #include <vector>
11 #include <queue>
12 #if defined DEBUG
13 FILE *in = fopen("test", "r");
14 #define out stdout
15 #else
16 FILE *in = fopen("birda.in", "r");
17 FILE *out = fopen("birda.out", "w");
18 #endif
19 #define pb push_back
20 #define iter(v) v::iterator
21 template<typename T> inline bool getd(T &x){
22 int c = fgetc(in);
;
24 while(c != '-' && c != EOF && !isdigit(c))c = fgetc(in);
;
26 if(c == '-'){
;
;
29 }
';
+ c - ';
32 if(minus)x = -x;
;
34 }
35 using namespace std;
36 /*==========================================================*/
+ , maxm = + , INF = 0x3f3f3f3f;
][maxm] = {};//循环数组
};
40
41 inline void init(){
42 getd(n), getd(m), getd(k);
43 int i;
] = m + ;
;i < n;++i){
46 getd(X[i]), getd(Y[i]);
] = m + X[i] + ;//“撞到”?
48 }
49 while(k--){
50 getd(i);
51 getd(L[i]), getd(H[i]);
52 }
53 }
54
55 inline bool safe(int i, int h){
;
;
58 }
59
60 inline void work(){
;
62 bool ok;
;i < n;++i){
;
^], ));
66 if(H[i] <= m)++score;
;j < min(H[i], m+);++j){
][j] != INF)ok = ;
69 else continue;
, j-Y[i]))
^][j-Y[i]] = min(cnt[i&^][j-Y[i]], cnt[i&][j]);
;k < H[i+];k += X[i],++t){
73 if(k > m)k = m;
, k))
^][k] = min(cnt[i&^][k], cnt[i&][j] + t);
76 if(k == m)break;
77 }
78 }
79 if(!ok){
);
81 return;
82 }
83 }
84 int ans = INF;
;i <= m;++i)//若能到达n-1,则一定能到达n
][i]);
87 fprintf(out, "1\n%d\n", ans);
88 }
89
90 int main(){
91
92 init();
93
94 work();
95
96 #if defined DEBUG
97 cout << endl << (double)clock() / CLOCKS_PER_SEC << " sec" << endl;
98 #endif
;
}
动态规划(转移方式稍有优化)
接下来……让我们来看我没有得分的day2:
还是送分题,直接枚举每个矩形然后累加就可以过……不过我强迫症发作写了二维前缀和- -
2 /*========================ASM.DEF=======================*/
3 /*======================================================*/
4 #include <cstdio>
5 #include <cctype>
6 #include <iostream>
7 #include <cmath>
8 #include <cstring>
9 #include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#if defined WJX_Asm_Def_DEBUG
FILE *in = fopen("test", "r");
#define out stdout
#else
FILE *in = fopen("wireless.in", "r");
FILE *out = fopen("wireless.out", "w");
#endif
inline bool getd(int &x){
int c = fgetc(in);
;
while(c != '-' && c != EOF && !isdigit(c))c = fgetc(in);
;
if(c == '-'){
x = ;
minus = ;
}
';
- ' + c;
;
}
/*===========================================================*/
;
}, S[maxn][maxn] = {};
int d, n;
inline void init(){
getd(d), getd(n);
int x, y;
while(n--){
getd(x), getd(y);
getd(pub[x+][y+]);
}
;x <= ;++x)//2-d Suffix
;y <= ;++y)
S[x][y] = S[x-][y] - S[x-][y-] + S[x][y-] + pub[x][y];
}
inline void work(){
, cnt = , i, j, i1, j1, i2, j2, s;
;i <= ;++i)
;j <= ;++j){
i1 = i - d - , j1 = j - d - ;//可以覆盖边线
i2 = i + d, j2 = j + d;
)i1 = ;
)j1 = ;
)i2 = ;
)j2 = ;
s = S[i2][j2] - S[i1][j2] - S[i2][j1] + S[i1][j1];
;
else if(s == Max)++cnt;
}
fprintf(out, "%d %d\n", cnt, Max);
}
int main(){
init();
work();
#if defined WJX_Asm_Def_DEBUG
cout << (double)clock() / CLOCKS_PER_SEC << endl;
#endif
;
}
二维前缀和
算是半道送分题吧。。。我的做法是反向dfs预处理出“在路径上”的节点,然后只对这些点做spfa即可。(不过似乎直接反向spfa就可以了……蠢了蠢了....)
2 /*========================ASM.DEF=======================*/
3 /*======================================================*/
4 #include <cstdio>
5 #include <cctype>
6 #include <iostream>
7 #include <cmath>
8 #include <cstring>
9 #include <algorithm>
10 #include <vector>
11 #include <queue>
12 #include <deque>
13 #include <list>
14 using namespace std;
15 #if defined WJX_Asm_Def_DEBUG
16 FILE *in = fopen("test", "r");
17 #define out stdout
18 #else
19 FILE *in = fopen("roadb.in", "r");
20 FILE *out = fopen("roadb.out", "w");
21 #endif
22 inline bool getd(int &x){
23 int c = fgetc(in);
;
25 while(c != '-' && c != EOF && !isdigit(c))c = fgetc(in);
;
27 if(c == '-'){
;
;
30 }
';
- ' + c;
;
34 }
35 #define iter(v) v::iterator
36 #define pb push_back
37 #define pf push_front
38 #define ppf pop_front
39 /*===========================================================*/
+ , INF = 0x3f3f3f3f;
41 list<int> adj[maxn];
42 vector<int> back[maxn];
43 int n, m, s, t;
44 int dis[maxn];
}, known[maxn] = {}, linked[maxn] = {};
46
47 void dfs(int cur){//判断是否与t联通
48 iter(vector<int>) it;
49 for(it = back[cur].begin();it !=back[cur].end();++it){
50 if(!known[*it]){
;
52 dfs(*it);
53 }
54 }
55 }
56
57 inline void init(){
58 getd(n), getd(m);
59 int x, y;
60 while(m--){
61 getd(x), getd(y);
62 if(x == y)continue;
63 adj[x].pb(y);
64 back[y].pb(x);
65 }
66 getd(s), getd(t);
, known[t] = , in_p[t] = ;
68 dfs(t);
69 iter(list<int>) it;
;i <= n;++i){
;
72 for(it = adj[i].begin();it != adj[i].end();++it)
;break;}
;
75 dis[i] = INF;
76 }
77 }
78 deque<int> Q;
};
80 inline void work(){
81 if(!in_p[s]){fprintf(out, "-1\n");return;}
, dis[s] = ;
83 int k;
84 iter(list<int>) it;
85 while(!Q.empty()){
;Q.ppf();
87 for(it = adj[k].begin();it != adj[k].end();++it){
88 if(!in_p[*it]){
89 it = adj[k].erase(it);
90 --it;
91 }
< dis[*it]){
;
94 if(inQ[*it])continue;
;
96 if(Q.empty() || dis[*it] <= dis[Q.front()])Q.pf(*it);//Small Label First
97 else Q.pb(*it);
98 }
99 }
}
if(dis[t] == INF)fprintf(out, "-1\n");
else fprintf(out, "%d\n", dis[t]);
}
int main(){
init();
work();
#if defined WJX_Asm_Def_DEBUG
cout << (double)clock() / CLOCKS_PER_SEC << endl;
#endif
;
}
最短路
这是这次联赛最有水平的一道题…
首先因为我太弱没有写过hash,我以为这题正解是高精度的优化,然后看了好久就是找不到优化点……最后还是直接把高精度敲上了。。(反正也没分。。。)
最后,我看到了金策的题解……(传送门:http://uoj.ac/blog/24) 然后照着思路仿写了一份,跑起来果然厉害...
2 /*========================ASM.DEF=======================*/
3 /*======================================================*/
4 #include <cstdio>
5 #include <cctype>
6 #include <iostream>
7 #include <cmath>
8 #include <cstring>
9 #include <algorithm>
10 #include <vector>
11 #include <queue>
12 #include <deque>
13 #include <ctime>
14 using namespace std;
15 #if defined WJX_Asm_Def_DEBUG
16 FILE *in = fopen("test", "r");
17 #define out stdout
18 #else
19 FILE *in = fopen("equationa.in", "r");
20 FILE *out = fopen("equationa.out", "w");
21 #endif
22 inline bool getd(int &x){
23 int c = fgetc(in);
;
25 while(c != '-' && c != EOF && !isdigit(c))c = fgetc(in);
;
27 if(c == '-'){
;
;
30 }
';
- ' + c;
;
34 }
35 #define iter(v) v::iterator
36 #define pb push_back
37 #define pf push_front
38 #define ppf pop_front
39 /*===========================================================*/
+ , maxm = + , maxl = + ;
}, a[maxn][maxl], amod[maxn] = {};
};
, basep;
};
45
46 inline void euler(){
};
48 int i, j;
;i < maxl;++i){
50 if(!not_p[i])P[Pcnt++] = i;
;j < Pcnt;++j){
52 if(i * P[j] > maxl)break;
;
)break;
55 }
56 }
57 }
58
59 inline void init(){
60 srand(time(NULL));
61 euler();
62 getd(n), getd(m);
63 int i, c;
;i <= n;++i){
65 c = fgetc(in);
66 while(!isdigit(c) && c != '-')c = fgetc(in);
67 if(c == '-'){
;
69 c = fgetc(in);
70 }
';
72 while(isdigit(c = fgetc(in)))
';
74 }
75 }
76
77 inline bool getamod(int p){
78 int i, j;
;
;i <= n;++i){
] % p;
;j < len[i];++j)
+ a[i][j]) % p;
;
85 }
86 return ans;
87 }
88
89 inline int f(int x, int p){
, ans = , t;
91 x %= p;
;i <= n;++i){
93 t = neg[i] ? p - amod[i] : amod[i];
94 ans = (ans + k * t) % p;
95 k = (k * x) % p;
96 }
97 return ans;
98 }
99
inline void work(){
int i, k, p, cnt = m;
};
i = lower_bound(P, P + Pcnt, (int)sqrt((double)m * n)) - P;
basep = P[i];
while(!getamod(basep))basep = P[--i];
;i < basep;++i)
;
k = ;
while(k || cnt > n){
--k;
p = P[rand() % Pcnt];
while(!getamod(p))p = P[rand() % Pcnt];
;i <= m;++i){
if(not_A[i])continue;
if(not_ans[i % basep]){
not_A[i] = ;
--cnt;
continue;
}
, --cnt;
}
}
fprintf(out, "%d\n", cnt);
;i <= m;++i)
if(!not_A[i])
fprintf(out, "%d\n", i);
}
int main(){
init();
work();
;
}
分段,用hash判断
NOIP2014 解题报告·水渣记的更多相关文章
- NOIp2014 解题报告
有史以来第一届面向社会征题的NOIp结束了.最开始以为面向社会征题会很难,但是这是我参加的最水的一次NOIp了. 由于停了两月的课,所以现在正在补文化科目就没时间打代码了.所以所有的题目就均不给出代码 ...
- NOIP2014解题报告
day 1 1.生活大爆炸版石头剪刀布(rps) 直接按照题意模拟即可 #include<cstdio> #include<algorithm> #include<cst ...
- 二模13day1解题报告
二模13day1解题报告 T1.发射站(station) N个发射站,每个发射站有高度hi,发射信号强度vi,每个发射站的信号只会被左和右第一个比他高的收到.现在求收到信号最强的发射站. 我用了时间复 ...
- 2011 ACM-ICPC 成都赛区解题报告(转)
2011 ACM-ICPC 成都赛区解题报告 首先对F题出了陈题表示万分抱歉,我们都没注意到在2009哈尔滨赛区曾出过一模一样的题.其他的话,这套题还是非常不错的,除C之外的9道题都有队伍AC,最终冠 ...
- POJ 1001 解题报告 高精度大整数乘法模版
题目是POJ1001 Exponentiation 虽然是小数的幂 最终还是转化为大整数的乘法 这道题要考虑的边界情况比较多 做这道题的时候,我分析了 网上的两个解题报告,发现都有错误,说明OJ对于 ...
- 【百度之星2014~初赛(第二轮)解题报告】Chess
声明 笔者近期意外的发现 笔者的个人站点http://tiankonguse.com/ 的非常多文章被其他站点转载.可是转载时未声明文章来源或參考自 http://tiankonguse.com/ 站 ...
- 夏令营提高班上午上机测试 Day 4 解题报告
我要是没记错的话,今天的题难度算挺适中的. *标程来自高天宇哥哥 T1:小G的字符串 题目描述 有一天,小 L 给小 G 出了这样一道题:生成一个长度为 n 的.全由小写英文字母构成的字符串,只能使用 ...
- GX/GZOI2019 day2 解题报告
GX/GZOI2019 day2 解题报告 题目链接 逼死强迫症 旅行者 旧词 t1 逼死强迫症 显然地,记 \(f(i)\) 为长度为 \(i\) 的木板的答案,可得: \(\\\) \[f(i)= ...
- Codeforces 524 解题报告
打的很快乐的一次比赛hiahiahia, 才A掉4题rating就涨了100+ 距离比赛\(3\)天了, 由于博主实在太颓, 又补掉了\(E\)题, 到现在才发解题报告 A. 语法题, 读入输出就行了 ...
随机推荐
- Part2-HttpClient官方教程-Chapter4-HTTP 认证
原文链接地址 HttpClient 提供对由 HTTP 标准规范定义的认证模式的完全支持.HttpClient 的认证框架可以扩展支持非标准的认证模式,比如 NTLM 和 SPNEGO. 4.1 用户 ...
- 完全教程 Aircrack-ng破解WEP、WPA-PSK加密利器
其 实关于无线基础知识的内容还是挺多的,但是由于本书侧重于BT4自身工具使用的讲解,若是再仔细讲述这些外围的知识,这就好比讲述DNS工具时还要把 DNS服务器的类型.工作原理及配置讲述一遍一样,哈哈, ...
- python中multiprocessing模块
multiprocess模块那来干嘛的? 答:利用multiprocessing可以在主进程中创建子进程.Threading是多线程,multiprocessing是多进程. #该模块和Threadi ...
- 基于ARM 构架(带MMU)的copy_from_user与copy_to_user详细分析
[转自:http://blog.chinaunix.net/uid-20543672-id-3195249.html] 在学习Linux内核驱动的时候,一开始就会碰到copy_from_use ...
- [hadoop][基本原理]zookeeper简单使用
代码:https://github.com/xufeng79x/ZkClientTest 1.简介 zookeeper的基本原理和使用场景描述可参考:[hadoop][基本原理]zookeeper基本 ...
- 1.ubuntu的安装
分两种 1. 在VMware中安装,则与Centos的安装类似 2. 在VirtualBox里安装 --> 1. 先“新建” 一个虚拟电脑 2. 根据需求编辑虚拟电脑的信息 (具体的大小.内存等 ...
- JDBC数据源连接池(4)---自定义数据源连接池
[续上文<JDBC数据源连接池(3)---Tomcat集成DBCP>] 我们已经 了解了DBCP,C3P0,以及Tomcat内置的数据源连接池,那么,这些数据源连接池是如何实现的呢?为了究 ...
- Django web框架之模板
1 模板: 什么是模板? html+模板语法 模版包括在使用时会被值替换掉的 变量,和控制模版逻辑的 标签. 2 模板语法: 1 变量:{{}} 深度查询: 通过句点符号 . 过滤器 filter { ...
- 今天开始学模式识别与机器学习(PRML),章节5.1,Neural Networks神经网络-前向网络。
今天开始学模式识别与机器学习Pattern Recognition and Machine Learning (PRML),章节5.1,Neural Networks神经网络-前向网络. 话说上一次写 ...
- C语言实现二叉排序树
程序以'#'结尾的二叉排序树. /*(双重指针 BSTree *T)问:数据结构中 二叉树建立结点为什么用 双重指针?详细解释下双重指针 答:指针的指针.因为树的结点要用指针描述.如果只用指针,作形参 ...