• Good Bye 2020 题解


    目前进度:A~G

    一万年没开过 vp 了,决定来看一看。

    然后开场就降智了,被 BC 连着卡。去看 DEF 发现全是傻逼题,以后被卡题我再不跳我就……就掉分呗(

    然后看 G。最近这 CF 都出的什么垃圾题啊,想起来又不难,写又好烦……

    甚至还卡空间。出字符串题只开 256MB???一万年后才过。

    看起来勉强可以升点分,然而打得这么难受的屑场给我分我也不想要……


    A

    容易发现答案是 (x_j-x_i) 的不同取值个数。

    出题人给的那个值域 1e5 的 challenge,我怎么只会 FFT 啊 /kk

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=100010,mod=998244353;
    #define MP make_pair
    #define PB push_back
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    inline ll read(){
    	char ch=getchar();ll x=0,f=0;
    	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f?-x:x;
    }
    inline int qmo(int x){return x+(x>>31?mod:0);}
    int n,a[maxn],ans;
    bool vis[maxn];
    void clear(){
    	ans=0;
    	FOR(i,0,50) vis[i]=false;
    }
    void solve(){
    	n=read();
    	FOR(i,1,n) a[i]=read();
    	FOR(i,1,n) FOR(j,i+1,n) if(!vis[a[j]-a[i]]) vis[a[j]-a[i]]=true,ans++;
    	printf("%d
    ",ans);
    	clear();
    }
    int main(){
    	int T=read();
    	while(T--) solve();
    }
    

    B

    最大那个肯定 +1。

    次大那个如果 +1 后不等于最大值也要 +1,否则不动。

    以此类推。注意相等的数的细节。

    出题人给的 challenge 是不是也是尽可能加就行了啊 /fad

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=100010,mod=998244353;
    #define MP make_pair
    #define PB push_back
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    inline ll read(){
    	char ch=getchar();ll x=0,f=0;
    	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f?-x:x;
    }
    inline int qmo(int x){return x+(x>>31?mod:0);}
    int n,a[maxn];
    void solve(){
    	n=read();
    	FOR(i,1,n) a[i]=read();
    	ROF(i,n,1){
    		if(i==n || a[i]+1!=a[i+1] && a[i]!=a[i+1]) a[i]++;
    	}
    	int ans=1;
    	FOR(i,1,n-1) if(a[i]!=a[i+1]) ans++;
    	printf("%d
    ",ans);
    }
    int main(){
    	int T=read();
    	while(T--) solve();
    }
    

    C

    这都想了这么久是不是退役了?

    注意到如果不存在长度为 2 和 3 的回文子串就合法。分奇偶讨论一下显然。

    然后无脑冲个 dp。

    出题人给的 challenge 似乎可以冲个动态 dp,懒得想了。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=100010,mod=998244353;
    #define MP make_pair
    #define PB push_back
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    inline ll read(){
    	char ch=getchar();ll x=0,f=0;
    	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f?-x:x;
    }
    inline int qmo(int x){return x+(x>>31?mod:0);}
    int n,f[maxn][2][2];
    char s[maxn];
    void solve(){
    	scanf("%s",s+1);
    	n=strlen(s+1);
    	FOR(i,0,n) f[i][0][0]=f[i][0][1]=f[i][1][0]=f[i][1][1]=1e9;
    	f[0][1][1]=0;
    	FOR(i,1,n){
    		FOR(a,0,1) FOR(b,0,1) FOR(c,0,1){
    			if(a || ((b || s[i]!=s[i-1]) && (c || s[i]!=s[i-2])))
    				f[i][a][b]=min(f[i][a][b],f[i-1][b][c]+a);
    		} 
    	}
    	printf("%d
    ",min(min(f[n][0][0],f[n][0][1]),min(f[n][1][0],f[n][1][1])));
    }
    int main(){
    	int T=read();
    	while(T--) solve();
    }
    

    D

    首先注意到,同种颜色最优解下是连通的。若不连通,可以只保留最大那个连通块,其它的分给别的颜色。

    那么此时一个方案的总代价,是对于每个点,包含在多少个颜色的连通块中,乘上点权的和。

    这等价于一个点的邻边中有多少种不同的颜色。这个数不能超过这个点的度数,且至少为 1。

    那么每次贪心取最大的就行了。显然可以还原出一种方案。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=100010,mod=998244353;
    #define MP make_pair
    #define PB push_back
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    inline ll read(){
    	char ch=getchar();ll x=0,f=0;
    	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f?-x:x;
    }
    inline int qmo(int x){return x+(x>>31?mod:0);}
    int n,w[maxn],deg[maxn],tmp[maxn],tl;
    ll ans;
    void clear(){
    	FOR(i,1,n) deg[i]=0;
    	tl=ans=0;
    }
    void solve(){
    	n=read();
    	FOR(i,1,n) w[i]=read();
    	FOR(i,1,2*n-2) deg[read()]++;
    	FOR(i,1,n) ans+=w[i];
    	printf("%lld ",ans);
    	FOR(i,1,n) FOR(j,1,deg[i]-1) tmp[++tl]=w[i];
    	sort(tmp+1,tmp+tl+1,greater<int>());
    	FOR(i,1,n-2){
    		ans+=tmp[i];
    		printf("%lld ",ans);
    	}
    	puts("");
    	clear();
    }
    int main(){
    	int T=read();
    	while(T--) solve();
    }
    

    E

    直接枚举 (j),然后变成求 (a_i&a_j)(a_i|a_j) 的和。

    按位讨论,没了。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=555555,mod=1000000007;
    #define MP make_pair
    #define PB push_back
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    inline ll read(){
    	char ch=getchar();ll x=0,f=0;
    	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f?-x:x;
    }
    inline int qmo(int x){return x+(x>>31?mod:0);}
    int n,sum[maxn];
    ll a[maxn];
    void solve(){
    	n=read();
    	FOR(i,1,n) a[i]=read();
    	FOR(i,0,59) sum[i]=0;
    	FOR(i,1,n) FOR(j,0,59) if((a[i]>>j)&1) sum[j]=(sum[j]+(1ll<<j))%mod;
    	int ans=0;
    	FOR(i,1,n){
    		int s1=0,s2=0;
    		FOR(j,0,59) if((a[i]>>j)&1){
    			s1=(s1+sum[j])%mod;
    			s2=(s2+(1ll<<j)%mod*n)%mod;
    		}
    		else{
    			s2=(s2+sum[j])%mod;
    		}
    		ans=(ans+1ll*s1*s2)%mod;
    	}
    	printf("%d
    ",ans);
    }
    int main(){
    	int T=read();
    	while(T--) solve(); 
    }
    

    F

    题面完美描述了线性基的构造过程,现在只需要快速模拟即可。

    容易发现,任意时候,线性基中的元素,和正在插入的元素(可能已经被消了几次),1 的位数不超过 2。

    对于目前在插入的元素,直接找到它的最大位对应的基底。如果不存在直接上去,如果存在就异或一下继续。

    然而这个复杂度还是平方级别的。可以被下面这个卡掉:

    11000
    01100
    00110
    00011
    
    插入 10000
    

    要解决这个问题也不难。复杂度会被卡是因为异或之后,新多出来的位对应的基底可能也存在。

    所以每次加入了基底,就对前面的基底回消。那么每个基底,除了最高位,对应的基底一定不存在。那么每次就只有常数次操作。

    要回消的基底数量可能很多,可以用并查集实现。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=555555,mod=1000000007;
    #define MP make_pair
    #define PB push_back
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    inline ll read(){
    	char ch=getchar();ll x=0,f=0;
    	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f?-x:x;
    }
    inline int qmo(int x){return x+(x>>31?mod:0);}
    struct vec{
    	int len,x[2],id;
    	vec(){len=x[0]=x[1]=id=0;}
    }a[maxn],b[maxn];
    int n,m,tmp[maxn],tl,fa[maxn];
    inline int qpow(int a,int b){
    	int ans=1;
    	for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) ans=1ll*ans*a%mod;
    	return ans;
    }
    inline int getfa(int x){
    	return x==fa[x]?x:fa[x]=getfa(fa[x]);
    }
    int main(){
    	n=read();m=read();
    	FOR(i,1,n){
    		a[i].len=read();
    		FOR(j,0,a[i].len-1) a[i].x[j]=read();
    		sort(a[i].x,a[i].x+a[i].len,greater<int>());
    		a[i].id=i;
    	}
    	FOR(i,1,m) fa[i]=i;
    	FOR(i,1,n){
    		while(a[i].len){
    //			printf("try %d %d %d
    ",a[i].len,a[i].x[0],a[i].x[1]);
    			int now=a[i].x[0];
    			if(!b[now].len){
    				b[now]=a[i];
    				break;
    			}
    			a[i].x[0]=a[i].x[1];
    			a[i].x[1]=0;
    			a[i].len--;
    			if(b[now].len==2){
    				a[i].len++;
    				a[i].x[a[i].len-1]=getfa(b[now].x[1]);
    				sort(a[i].x,a[i].x+a[i].len,greater<int>());
    				if(a[i].len==2 && a[i].x[0]==a[i].x[1]) a[i]=vec();
    			}
    		}
    		if(a[i].len==2){
    			int now=a[i].x[0],to=a[i].x[1];
    			fa[getfa(now)]=to;
    		}
    //		printf("a[i].len=%d,getfa(2)=%d
    ",a[i].len,getfa(2));
    	}
    	FOR(i,1,m) if(b[i].len) tmp[++tl]=b[i].id;
    	sort(tmp+1,tmp+tl+1);
    	printf("%d %d
    ",qpow(2,tl),tl);
    	FOR(i,1,tl) printf("%d ",tmp[i]); 
    }
    /*
    3 3
    2 2 3
    2 1 2
    2 3 1
    */
    

    看了官方题解,发现似乎建个图就不用考虑那么多东西了?

    (话说只有两个位我还没想到建图,那我可真是没救了


    G

    先求出所有长度 (le 10^6)(s_i)(设为 (s_0dots,s_{mx})),显然 (mx=O(log)),且长度和也为线性。

    询问串 (w)(s_i) 出现多少次,如果 (|s_i|le 10^6) 就随便搞了,我选择了离线后 AC 自动机。然后就卡空间卡到自闭。

    否则,有两种可能:(w) 跨过 (t_{i-1}) 或者 (w) 完全在 (s_{i-1}) 中出现。

    这可以用 (w) 跨过 (t_j(mx<jle i-1)) 的次数和 (w) 完全在 (s_{mx+1}) 中出现的次数表示。后者也是离线后 AC 自动机。

    前者直接哈希,看 (w) 的前缀和 (s_{mx+1}) 的后缀是否一样。然后求个前缀和。(然后你发现又要一个 (n|Sigma|) 的数组,慢慢卡吧)

    居然写上 4k 了。

    官方题解好像没这么垃圾,到时候研究一下,写就算了。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=1111111,mod=1000000007,bs1=61,bs2=251,mod1=1004535809,mod2=999911659,hhh=1000000;
    #define MP make_pair
    #define PB push_back
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    inline ll read(){
    	char ch=getchar();ll x=0,f=0;
    	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f?-x:x;
    }
    inline int qmo(int x){return x+(x>>31?mod:0);}
    int n,q,mx,len[22],ans[maxn],cnt,id[maxn],fail[maxn],que[maxn],h,r,sss[maxn],x[maxn],fl,ch[maxn][26];
    int pre1[maxn*2],pre2[maxn*2],suf1[maxn*2],suf2[maxn*2];
    char s0[maxn],s[maxn*2],t[maxn],str[maxn*2];
    bool ok[maxn];
    struct fuck_the_mle{
    	int at,pos,id;
    	bool operator <(const fuck_the_mle &f)const{
    		if(at!=f.at) return at<f.at;
    		return pos<f.pos;
    	}
    }fff[maxn];
    inline int qpow(int a,int b){
    	int ans=1;
    	for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) ans=1ll*ans*a%mod;
    	return ans;
    } 
    void insert(const char *s,int d){
    	int now=0,l=strlen(s+1);
    	FOR(i,1,l){
    		int p=s[i]-'a';
    		if(!ch[now][p]) ch[now][p]=++cnt;//,printf("add %d
    ",cnt);
    		now=ch[now][p];
    	}
    	id[d]=now;
    }
    void build(){
    	h=1;r=0;
    	FOR(i,0,25) if(ch[0][i]) que[++r]=ch[0][i];
    	while(h<=r){
    		int now=que[h++];
    		FOR(i,0,25) if(ch[now][i]){
    			fail[ch[now][i]]=ch[fail[now]][i];
    			que[++r]=ch[now][i];
    		}
    		else ch[now][i]=ch[fail[now]][i];
    	}
    }
    void work(int vs){
    //	printf("work %d
    ",vs);
    	FOR(i,1,cnt) sss[i]=0;
    	int now=0,l=strlen(s+1);
    	FOR(i,1,l){
    		int p=s[i]-'a';
    		now=ch[now][p];
    		sss[now]++;
    //		printf("add at %d
    ",now);
    	}
    	ROF(i,r,1) sss[fail[que[i]]]=(sss[fail[que[i]]]+sss[que[i]])%mod;
    //	FOR(i,1,cnt) printf("%d ",sss[i]);
    //	puts("");
    	int tmp=qpow(2,mod-1-vs);
    	FOR(i,1,q) if(vs==min(mx,x[i])) ans[i]=(ans[i]+1ll*sss[id[i]]*tmp)%mod;
    //	FOR(i,1,q){
    //		printf("%lld ",1ll*ans[i]*qpow(2,x[i])%mod);
    //	}
    //	puts("");
    }
    int main(){
    	n=read();q=read();
    	scanf("%s%s",s0+1,t+1);
    	len[0]=strlen(s0+1);
    	strcpy(s+1,s0+1);
    	FOR(i,1,n){
    		mx=i;
    		strcpy(str+1,s+1);
    		s[len[i-1]+1]=t[i];
    		strcat(s+1,str+1);
    		len[i]=2*len[i-1]+1; 
    		if(len[i]>=hhh) break;
    	}
    	FOR(i,1,len[mx]){
    		pre1[i]=(1ll*pre1[i-1]*bs1+s[i]-'a')%mod1;
    		pre2[i]=(1ll*pre2[i-1]*bs2+s[i]-'a')%mod2;
    	}
    	int pr1=1,pr2=1;
    	ROF(i,len[mx],1){
    		suf1[i]=(suf1[i+1]+1ll*(s[i]-'a')*pr1)%mod1;
    		suf2[i]=(suf2[i+1]+1ll*(s[i]-'a')*pr2)%mod2;
    		pr1=1ll*pr1*bs1%mod1;
    		pr2=1ll*pr2*bs2%mod2;
    	}
    /*	FOR(i,mx+1,n){
    		FOR(j,0,25) sum[i][j]=sum[i-1][j];
    		sum[i][t[i]-'a']=(sum[i][t[i]-'a']+qpow(2,mod-1-i))%mod;
    	}*/
    	FOR(_,1,q){
    		x[_]=read();
    		scanf("%s",str+1);
    		int l=strlen(str+1);
    		insert(str,_);
    		if(x[_]<=mx || l>len[mx]) continue; 
    		FOR(i,1,l) ok[i]=true;
    		int hs1=0,hs2=0;
    		FOR(i,1,l-1){
    			hs1=(1ll*hs1*bs1+str[i]-'a')%mod1;
    			hs2=(1ll*hs2*bs2+str[i]-'a')%mod2;
    			ok[i+1]&=hs1==suf1[len[mx]-i+1] && hs2==suf2[len[mx]-i+1];
    		}
    		hs1=hs2=0;
    		int pr1=1,pr2=1;
    		ROF(i,l,2){
    			hs1=(hs1+1ll*(str[i]-'a')*pr1)%mod1;
    			hs2=(hs2+1ll*(str[i]-'a')*pr2)%mod2;
    			ok[i-1]&=hs1==pre1[l-i+1] && hs2==pre2[l-i+1];
    			pr1=1ll*pr1*bs1%mod1;
    			pr2=1ll*pr2*bs2%mod2;
    		}
    		FOR(i,1,l) if(ok[i]) fff[++fl]=(fuck_the_mle){str[i]-'a',x[_],_};
    //		FOR(i,1,l) if(ok[i]) ans[_]=(ans[_]+sum[x[_]][str[i]-'a'])%mod;
    	}
    	sort(fff+1,fff+fl+1);
    	int cur=1;
    	FOR(i,0,25){
    		while(cur<=fl && fff[cur].at<i) cur++;
    		int sum=0;
    		FOR(j,mx+1,n){
    			if(t[j]-'a'==i) sum=(sum+qpow(2,mod-1-j))%mod;
    			while(cur<=fl && fff[cur].at==i && fff[cur].pos<j) cur++;
    			while(cur<=fl && fff[cur].at==i && fff[cur].pos==j){
    				ans[fff[cur].id]=(ans[fff[cur].id]+sum)%mod;
    				cur++;
    			}
    		}
    	}
    	build();
    	MEM(s,0);
    	strcpy(s+1,s0+1);
    	work(0);
    	FOR(i,1,n){
    		strcpy(str+1,s+1);
    		s[len[i-1]+1]=t[i];
    		strcat(s+1,str+1);
    		len[i]=2*len[i-1]+1;
    //		printf("%s
    ",s+1);
    		work(i);
    		if(len[i]>=hhh) break;
    	}
    	FOR(i,1,q){
    		ans[i]=1ll*ans[i]*qpow(2,x[i])%mod;
    		printf("%d
    ",ans[i]);
    	}
    }
    

    H

    看都没看。这么长的题面先咕着。

    I

    交互压轴?跑路了。

  • 相关阅读:
    UTF-8和GBK的区别
    JSP页面中的pageEncoding和contentType两种属性
    tomcat中reloadable作用
    为什么Servlet修改之后,Tomcat都得重启,servlet才会生效!
    windows下mysql表名不自动转换小写配置
    导入mysql文件提示“ASCII '' appeared in the statement”
    request:getParameter和getAttribute区别
    Eclipse常用快捷键
    For input string: "null"
    国内外知名IT科技博客(强烈推荐)
  • 原文地址:https://www.cnblogs.com/1000Suns/p/14219810.html
Copyright © 2020-2023  润新知