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;
}
自觉忽略F题...