最近做了两场cf,通过了当中所有的题目,稍稍做下总结
Codeforces Round #325 (Div. 1)
这场是我排名最靠前的一次(23),虽然04写的比较慢,但是幸运的猜出了03,05和06都是短代码的可做题,然而并没有时间去看,这说明代码能力还是很重要的
A:有n个小孩依次去看牙齿,每个小孩看的时候会对后面的小孩造成等差递减的伤害,假如小孩不能承受这个伤害就会逃跑,问最后有几个小孩去看了牙齿,n<=4000
分析:比较简单的题目,暴力模拟每个小孩的看牙情况,用一个数组记录小孩是否还在队列当中
B:给出一张3*n的地图,有些位置有列车,列车每次向左行驶两格,行人最初在第一列,每次向右走一格,之后可以决定向上或者向下走一格(不超出地图),问行人最后是否有可能到达最后一列。
分析:可以转换坐标系,变成行人每次向右走三格之后决定向上或向下,之后就是一个简单的dp
C:A最初只有一个苹果,B最初只有一个橘子,现在要你构造一个01串操作序列,假如操作是0,则B拿A当前所具有苹果和橘子,否则A对B做相同的事,要求最后A和B的苹果数之和为x,橘子数之和为y.( x,y<=1018 )
分析:是一道比较巧妙的数学题,比赛的时候用欧几里德算法带进去算了一下,正好满足!于是就通过了这题
题解给了一个不为人知的数据结构:https://en.wikipedia.org/wiki/Stern%E2%80%93Brocot_tree
D:D是一个挺无聊的折半暴搜,虽然很简单,但是还是码了我一个小时之久,主要是一开始题目看错了。。。。
E:n个数,从中选出一个非空集合,在另外选出一个数,要求集合的gcd不为1且这个gcd和另外选择的数互质
分析:比较常用的筛法,假如把题目变成选择两个不同的数,要求gcd为1,那么我们可以先求 cnt[x]代表是x的倍数的数有多少个 ,筛一遍之后,我们可以先忽略不同这个要求,那么gcd是x的倍数的选法就是 cnt[x]2 ,之后再套用莫比乌斯函数暴力容斥即可得到答案,最后再减去1的数目即可。
对于这道题,也类似搞搞,不同之处在于他要求所选集合gcd不为1,因此我们最后再剪掉选择集合gcd==1形成的方案数,而后面也可以用莫比乌斯暴力容斥
代码极短
#include<bits/stdc++.h>
using namespace std;
const int Maxn=10000002,M=1e9+7;
typedef long long Int;
int miu[Maxn],cnt[Maxn];
int n;
int xp[500020];
int main()
{
xp[0]=1;
scanf("%d",&n);
for(int i=1;i<=n;i++)xp[i]=(xp[i-1]+xp[i-1])%M;
for(int i=1;i<=n;i++)
{
int x;scanf("%d",&x);
cnt[x]++;
}
int ans=0;
miu[1]=1;
for(int i=1;i<Maxn;i++)
{
for(int j=i+i;j<Maxn;j+=i)
{
miu[j]-=miu[i];
cnt[i]+=cnt[j];
}
if(!cnt[i]||!miu[i])continue;
ans+=miu[i]*(xp[cnt[i]]-1)*(Int)(cnt[i]-n)%M;
if(ans>=M)ans-=M;
if(ans<0)ans+=M;
}
printf("%d\n",ans);
}
F:给一个长<1000的数字串,给两个长度均为d且不含前导0的L和R,要求L~R之间有多少个串满足至少有一个长度>=d/2的子串是原数字串的子串。d<=50
这道题比赛的时候并没有人通过这道题,当时也是被吓的题目都没读过。然而今天读了一下,发现难度比我想象的要低很多。L~R之间有多少个满足的,看这样的数据范围很容易想到数位dp,关键是状态,由于要求是原串的子串,那么我们只需要知道当前匹配的最长原串子串是怎么样的即可。很容易想到后缀自动机,由于长度只有1000,那么总结点数也只有2000,放在状态里面一点也不过分。当然,后缀自动机只知道在那个节点还并不能知道当前串长是多少,由于d只有50,我们可以在一维代表长度,转移的时候暴力枚举填充的数就可以通过这道题
#include<bits/stdc++.h>
using namespace std;
const int Maxn=2020,M=1e9+7;
string s;
int last,sz;
int ml[Maxn],f[Maxn],ch[Maxn][1