CF Good Bye 2020 题解&总结 A~G
众所周知这种手速场是掉分好时机。
前200人均切7题,由于我没有切G导致400+。
不过竟然没有掉分真是令人震惊呢。
血的教训:
以后都用万能头文件。
A
求两两之间的差不重复的有多少个。
范围小,暴力即可。
B
比较显然的贪心:丢进桶中,从大往小做。如果当前位置大于等于\(2\),后面位置等于\(0\),就分一个到后面去。
C
卡题了。虽然切了但是血亏。
发现\(O(26^2n)\)的DP会MLE,所以把状态改成:\(f_{i,0/1,0/1}\),后两个状态表示后面两个位置是否被改过。
如果两个位置都改过了,那么可以认为两个位置不同。因为字符集大小比较大,所以肯定存在方案调整使得两个位置不同,并且满足其它的不等关系。
D
显然每个联通块一定是连续的;否则可以只保留那个比较大的连通块。
考虑一个点\(x\)的贡献为它所属的不同连通块个数。显然最多属于\(deg_x\)个。
可以发现把一个连通块分成两个连通块,交界的点只有一个。
增量法搞。一开始只有一个连通块,将所有\(deg_x\)减一。每次找到\(deg_x\)不为\(0\)的权值最大的点\(x\),将其权值加入答案并把\(deg_x\)减一。
E
由于ll事先看了下发现它很水提醒了我们,所以在切A之后立即切了E。
显然可以枚举\(j\),分别算\(i\)和\(k\)的贡献和乘起来。
计算贡献的时候可以先预处理对于每一位,这一位上是\(1\)的数有多少个。
F
卡题了,还挂了4次,血亏。
可以抽象成一个图。先不考虑自环,则最终形成的图中,如果出现环,那么环上的一条边可以被其它边替代;所以最终形成的图是个森林。考虑自环,如果一棵树中存在一个自环,那么树中的每个节点都可以任意调整。
按顺序加边。加入一个自环时,如果树中没有自环就加入;加入一条普通边时,如果不在同个连通块,并且不是两个连通块中都有自环,那么就加入。实现的时候搞个超级点\(0\),连自环的时候和\(0\)连边,连普通边的时候直接判断是否在同个连通块中。
G
最上面的那张图已经清楚地表明了一切。
先将字符串扩展成最小的\(s_i\),使刚好满足\(|s_i|\ge |w|\)。然后答案分成两部分:\(s_i\)内部的贡献乘\(2^{k-i}\),和对于所有\(j\in(i,k]\),\(s_it_js_i\)跨过中点的贡献。
前者暴力搞。对于后者,分别找\(lmx,rmx\),\(lmx\)表示最长的\(w\)的前缀匹配\(s_i\)的后缀的长度,即\(w[1..lmx]=s_i[|s_i|-lmx+1..|s_i|]\)。\(rmx\)类似。可以强行哈希或exkmp搞出来。
分别处理正反串kmp的数组\(p_i,q_i\),分别以此建树。设\(x\)和\(y\)为贡献时的第一个\(s_i\)的后缀和第二个\(s_i\)的前缀的长度,如果\(x+y+1=n\),\(w[x+1]=t[j]\),\(lmx\in subtree_p(x),rmx\in subtree_q(y)\),那么这组\((x,y)\)就可以贡献到。由于询问的\((lmx,rmx)\)只有一个,\(t[j]\)只有\(26\)种不同的取值,直接\(O(|w|)\)处理出来每个取值是什么时的答案。最后统计一下\(t_j\)相同时的贡献之和,随便计算一下即可。
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define N 1000005
#define ll long long
#define mo 1000000007
ll qpow(ll x,ll y=mo-2){
ll r=1;
for (;y;y>>=1,x=x*x%mo)
if (y&1)
r=r*x%mo;
return r;
}
int n,m,Q;
char s0[N],t[N];
char w[N],v[N];
int k,len;
int p[N],q[N];
char s[N*4],s_[N*4];
int ns;
int pw[N*4];
int bf(){
int res=0;
for (int i=1,j=0;i<=ns;++i){
while (j && w[j+1]!=s[i])
j=p[j];
if (w[j+1]==s[i]){
++j;
if (j==len)
res++,j=p[j];
}
}
return res;
}
ll ans;
int lmx,rmx;
#define mo2 1000000009
struct hsh{
int x,y;
};
hsh operator+(hsh a,hsh b){return {(a.x+b.x)%mo,(a.y+b.y)%mo2};}
hsh operator+(hsh a,int b){return {(a.x+b)%mo,(a.y+b)%mo2};}
hsh operator*(hsh a,int b){return {(ll)a.x*b%mo,(ll)a.y*b%mo2};}
bool eql(hsh a,hsh b){return a.x==b.x && a.y==b.y;}
int mxsuc(char w[],char s[]){
int res=0;
hsh hs,hw,p;
hs=hw={0,0};
p={1,1};
for (int i=ns,j=1;i>=1 && j<=len;--i,++j){
hs=hs*26+(s[i]-'a');
hw=hw+p*(w[j]-'a');
if (eql(hs,hw))
res=j;
p=p*26;
}
return res;
}
void init(){
memcpy(s_,s,sizeof(char)*(ns+1));
memcpy(v,w,sizeof(char)*(len+1));
reverse(s_+1,s_+ns+1);
reverse(v+1,v+len+1);
q[1]=0;
for (int i=2,j=0;i<=len;++i){
while (j && v[j+1]!=v[i])
j=q[j];
if (v[j+1]==v[i])
++j;
q[i]=j;
}
lmx=mxsuc(w,s);
rmx=mxsuc(v,s_);
}
int anc[N],buc[26];
vector<int> tc[26],ts[26];
int sum[26];
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
pw[0]=1;
for (int i=1;i<=4000000;++i)
pw[i]=pw[i-1]*2%mo;
scanf("%d%d%s%s",&n,&Q,s0+1,t+1);
m=strlen(s0+1);
for (int i=0;i<26;++i){
tc[i].push_back(0);
ts[i].push_back(0);
}
for (int i=1;i<=n;++i){
tc[t[i]-'a'].push_back(i);
(sum[t[i]-'a']+=qpow(2,mo-1-i))%=mo;
ts[t[i]-'a'].push_back(sum[t[i]-'a']);
}
while (Q--){
scanf("%d%s",&k,w+1);
len=strlen(w+1);
p[1]=0;
for (int i=2,j=0;i<=len;++i){
while (j && w[j+1]!=w[i])
j=p[j];
if (w[j+1]==w[i])
++j;
p[i]=j;
}
ns=m;
for (int i=1;i<=ns;++i)
s[i]=s0[i];
ans=0;
int i=0;
for (;i<k && ns<len;){
++i;
s[ns+1]=t[i];
for (int i=1;i<=ns;++i)
s[ns+1+i]=s[i];
ns=ns*2+1;
}
(ans+=(ll)bf()*pw[k-i])%=mo;
if (i==k){
printf("%lld\n",ans);
continue;
}
init();
memset(anc,0,sizeof(int)*(len+1));
for (int x=rmx;1;x=q[x]){
anc[x]=1;
if (x==0)
break;
}
memset(buc,0,sizeof buc);
for (int x=lmx;1;x=p[x]){
if (anc[len-1-x])
buc[w[x+1]-'a']++;
if (x==0)
break;
}
for (int j=0;j<26;++j){
int p=upper_bound(tc[j].begin(),tc[j].end(),k)-tc[j].begin()-1;
int q=upper_bound(tc[j].begin(),tc[j].end(),i)-tc[j].begin()-1;
(ans+=(ll)(ts[j][p]-ts[j][q])*buc[j]%mo*pw[k])%=mo;
}
ans=(ans+mo)%mo;
printf("%lld\n",ans);
}
return 0;
}
H
没看题意。
I
没看题意。
感觉这种比赛一卡题人就没了。
前6题人均AC。唯一有点区分度的就是G题,后面的题都是在神仙打架了。
这次最亏的大概就是F没想好就挂了4次和G题头文件没有写全了。