Educational Codeforces Round 7
A:题意:给出一个序列,形式为1,1,2,1,2,3,1,2,3,4,......每个位置上是一个数而不是一个数位,为第n为是什么。(n<=10^14)
好老的题了,就是等差数列,原本还想二分,看到n范围就果断枚举了。
#include <iostream> #include <cstring> #include <cstdlib> #include <string> #include <cstdio> #include <algorithm> #include <cmath> #include <ctime> #define Int long long using namespace std; Int n; int main() { cin>>n; Int i; for(i = 1;i <= 1e8;i ++) { if(((1ll + i) * i) / 2 >= n) { break; } } i = i - 1; cout<<n - ((1ll + i) * i) / 2; return 0; }
B:题意:给出一个24小时制的时间,问过去n分钟之后的24小时制时间是多少。(n<=10^4)
模拟就是了,如果答案是个位数就在前面添个0.
#include <iostream> #include <cstring> #include <cstdlib> #include <string> #include <cstdio> #include <algorithm> #include <cmath> #include <ctime> using namespace std; int getint() { char c = 'd'; int ret = 0; while(c < '0' || c > '9') c = getchar(); while(c >= '0' && c <= '9') ret = ret * 10 + c - '0',c = getchar(); return ret; } int A,B,a,b; int main() { A = getint(); B = getint(); a = getint(); b = a % 60; a = a / 60; A += a; B += b; A = A + (B / 60); B %= 60; A %= 24; if(A <= 9) cout<<0<<A; else cout<<A; cout<<':'; if(B <= 9) cout<<0<<B; else cout<<B; return 0; }
C:题意:给出一段序列,每次询问l到r之间与x不相等的数出现在什么位置。(任意输出一个位置)。(序列长200000)。
一眼想到了树套树,明显数据结构学傻了。
首先如果A[l]!=x,那么答案就是l,否则我们看与l不同的最近的下一个数在哪儿就行了,这个可以o(n)预处理。
#include <iostream> #include <cstring> #include <cstdlib> #include <string> #include <cstdio> #include <algorithm> #include <cmath> #include <ctime> using namespace std; int n,m,A[200010],next[200010],l,r,x; int main() { scanf("%d%d",&n,&m); for(int i = 1;i <= n;i ++) scanf("%d",&A[i]); next[n] = n + 1; for(int i = n - 1;i >= 1;i --) next[i] = (A[i] == A[i + 1]) ? next[i + 1] : i + 1; for(int i = 1;i <= m;i ++) { scanf("%d%d%d",&l,&r,&x); if(A[l] != x) printf("%d\n",l); else printf("%d\n",(next[l] <= r) ? next[l] : -1); } return 0; }
D:题意:给出n(500000),你需要把1-n每个数两遍填入一个长为2*n的数组中,填之后有一个代价,代价就是对于每一个i,会产生(n-i)*|d(i)-n+i|的代价,代价之和就是答案,d(i)是i这个数两个位置的距离。最小化代价,输出你填的序列。
看了一看答案仿佛是0!!!因为我们只要保证每个数都相距n-i就行了,于是我们分奇数偶数进行构造,分别占n的长度,但是构造的时候发现n是个很大的麻烦,貌似会影响奇偶导致位置不够,我们有发现i=n是答案一定是0!!所以直接n--,吧其他的填完之后n随便填就可以了。
#include <iostream> #include <cstring> #include <cstdlib> #include <string> #include <cstdio> #include <algorithm> #include <cmath> #include <ctime> using namespace std; int n,A[1000010]; int main() { scanf("%d",&n); for(int i = 1;i <= n - 1;i += 2) A[(i + 1) / 2] = A[n - i / 2] = i; for(int i = 2;i <= n - 1;i += 2) A[n + i / 2] = A[2 * n - i / 2] = i; for(int i = 1;i <= 2 * n;i += 1) printf("%d ",(A[i] == 0) ? n : A[i]); return 0; }
E:题意:一棵树,根为1,每个叶子上有一只蚂蚁,每一时刻所有蚂蚁可以往父亲节点移一下,但是除了根之外不能有节点有同时两个蚂蚁存在,问所有蚂蚁到根的最短时间。(树大小5*10^5)
首先1的每棵子树一定是互相独立的。
其次我们这样考虑,设当前仅仅在第i层有k只蚂蚁,那么时间一定是i+k-1,因为他们可以排成一条链一起往上跳!。
所以说当有更深的节点存在时,我们这样考虑!设当前答案为x,在y层有一只蚂蚁(y>=x,按深度递增考虑)。
如果x>=y,那么x+1,因为可以想成上面的点自己慢慢跑,而y层的这个点先跑到与上面相同层数去,再一起跑就行了,就相当于多了一个相同层的点。
否则x=y,因为上面的点已经跑完了,但是y这只蚂蚁可能还没有及时跑到相同层(即没有和之前的蚂蚁接成一条链),所以总时间会被拖长。
对于每个1的子树求一个x,那么max(x + 1)就是答案了。
#include <iostream> #include <cstring> #include <cstdlib> #include <string> #include <cstdio> #include <algorithm> #include <cmath> #include <ctime> using namespace std; struct dp{int dep;int num; };dp Dp[500010]; struct node {int to;int next; };node bian[1000010]; int size,first[500010],p[500010],Ans = -1,n,a,b,tot = 0; bool comp(const dp &x,const dp &y) {return x.dep < y.dep;}; void inser(int x,int y) { size ++; bian[size].to = y; bian[size].next = first[x]; first[x] = size; } void dfs(int x,int Anc,int depth) { int son = 0; for(int u = first[x];u;u = bian[u].next) if(bian[u].to != Anc) son ++,dfs(bian[u].to,x,depth + 1); if(son == 0) { if(p[depth] == 0) { tot ++; p[depth] = tot; Dp[tot].num = 1; Dp[tot].dep = depth; } else Dp[p[depth]].num ++; } } int main() { scanf("%d",&n); for(int i = 2;i <= n;i ++) { scanf("%d%d",&a,&b); inser(a,b); inser(b,a); } for(int u = first[1];u;u = bian[u].next) { for(int i = 1;i <= tot;i ++) p[Dp[i].dep] = 0; tot = 0; dfs(bian[u].to,1,0); sort(Dp + 1,Dp + tot + 1,comp); int ret = -1; for(int i = 1;i <= tot;i ++) ret += (Dp[i].dep > ret) ? Dp[i].dep - ret + Dp[i].num - 1 : Dp[i].num; Ans = max(Ans,ret + 1); } cout<<Ans; return 0; }