zoukankan      html  css  js  c++  java
  • 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}),和对于所有(jin(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])(lmxin subtree_p(x),rmxin 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
    ",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
    ",ans);
    	}
    	return 0;
    }
    
    

    H

    没看题意。


    I

    没看题意。


    感觉这种比赛一卡题人就没了。

    前6题人均AC。唯一有点区分度的就是G题,后面的题都是在神仙打架了。

    这次最亏的大概就是F没想好就挂了4次和G题头文件没有写全了。

  • 相关阅读:
    Python项目生成requirements.txt的多种方式
    标准的Flask启动文件
    Flask的错误日志处理和|ORM操作
    Django的model中创建表
    Redis的删除机制、持久化 主从
    RabbitMQ 消息队列
    IP地址与子网掩码逐位相与
    IP地址转二进制
    一款很好用的工具
    放球问题
  • 原文地址:https://www.cnblogs.com/jz-597/p/14216441.html
Copyright © 2011-2022 走看看