• Educational Codeforces Round 70 题解


    噩梦场。

    题目出奇的难,好像一群外国老哥看 A 看着看着就哭了……


    A

    找到 (b) 最低的 (1),这个 (1) 肯定要跟 A 中的一个 (1) 搭配,而且是能搭配的 (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 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 int read(){
        int x=0,f=0;char ch=getchar();
        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;
    }
    int t,n,m;
    char a[maxn],b[maxn];
    int main(){
    	t=read();
    	while(t--){
    		scanf("%s",a+1);scanf("%s",b+1);
    		n=strlen(a+1);m=strlen(b+1);
    		int at,ans=0;
    		ROF(i,m,1) if(b[i]=='1'){at=n-(m-i);break;}
    		while(at>0 && a[at]=='0') at--,ans++;
    		printf("%d
    ",ans);
    	}
    }
    

    B

    大力枚举 (i,j)。对于每个 (i,j)(O(n)) 算,每次就是问在相邻两个数之间最少加多少个数。特别注意相邻两个数相同的情况。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=2000200,mod=998244353;
    #define MP make_pair
    #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 int read(){
        int x=0,f=0;char ch=getchar();
        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;
    }
    int n,ok[10][10][111],okk[10][10][10];
    char s[maxn];
    int main(){
    	scanf("%s",s+1);
    	n=strlen(s+1);
    	MEM(ok,0x3f);MEM(okk,0x3f);
    	FOR(i,0,9) FOR(j,0,9){
    		ok[i][j][0]=0;
    		FOR(l,0,99){
    			ok[i][j][l+i]=min(ok[i][j][l+i],ok[i][j][l]+1);
    			ok[i][j][l+j]=min(ok[i][j][l+j],ok[i][j][l]+1);
    		}
    		FOR(k,1,110) okk[i][j][k%10]=min(okk[i][j][k%10],ok[i][j][k]);
    		if(!i || !j) okk[i][j][0]=1;
    //		FOR(k,0,9) printf("ok[%d][%d][%d]=%d
    ",i,j,k,ok[i][j][k]);
    	}
    	FOR(i,0,9){
    		FOR(j,0,9){
    			int ans=0;
    			bool flag=true;
    			FOR(k,2,n){
    				int x=okk[i][j][(s[k]-s[k-1]+10)%10];
    				x=max(x-1,0);
    				if(x>=1e9){printf("-1 ");flag=false;break;}
    				ans+=x;
    			} 
    			if(flag) printf("%d ",ans);
    		}
    		puts("");
    	}
    }
    

    C

    毒瘤玩意……当然可能是我写复杂了。

    上下和左右互不干扰,分开考虑。以上下为例。

    把上看成 (1),下看成 (-1),那么竖直方向一共跨过了最大前缀和-最小前缀和单位。

    不妨枚举在哪里插入字符,然后瞎合并一通。

    需要很多东西,比如每个前缀的后缀和的后缀最大值。(smg……)

    不保证代码能让大家都理解。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=200020,mod=998244353;
    #define MP make_pair
    #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 int read(){
        int x=0,f=0;char ch=getchar();
        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;
    }
    int t,n,n1,n2,pre1[maxn],suf1[maxn],pre2[maxn],suf2[maxn];
    int mnpre1[maxn],mxpre1[maxn],mnpre2[maxn],mxpre2[maxn],mnsuf1[maxn],mxsuf1[maxn],mnsuf2[maxn],mxsuf2[maxn];
    int s1[maxn],s2[maxn];
    ll ans;
    char s[maxn];
    void calc(int n,int a[],int pre[],int suf[],int mnpre[],int mxpre[],int mnsuf[],int mxsuf[]){
    	FOR(i,1,n) pre[i]=pre[i-1]+a[i];
    	ROF(i,n,1) suf[i]=suf[i+1]+a[i];
    	FOR(i,1,n) mnpre[i]=a[i]+min(0,mnpre[i-1]),mxpre[i]=a[i]+max(0,mxpre[i-1]);
    	ROF(i,n,1) mnsuf[i]=min(mnsuf[i+1],suf[i]),mxsuf[i]=max(mxsuf[i+1],suf[i]);
    //	FOR(i,1,n) printf("pre[%d]=%d,suf[%d]=%d,mnpre[%d]=%d,mxpre[%d]=%d,mnsuf[%d]=%d,mxsuf[%d]=%d
    ",i,pre[i],i,suf[i],i,mnpre[i],i,mxpre[i],i,mnsuf[i],i,mxsuf[i]);
    }
    int main(){
    	t=read();
    	while(t--){
    		scanf("%s",s+1);
    		n=strlen(s+1);
    		n1=n2=0;
    		FOR(i,1,n){
    			if(s[i]=='W') s1[++n1]=1;
    			else if(s[i]=='S') s1[++n1]=-1;
    			else if(s[i]=='A') s2[++n2]=1;
    			else s2[++n2]=-1;
    		}
    		calc(n1,s1,pre1,suf1,mnpre1,mxpre1,mnsuf1,mxsuf1);
    		calc(n2,s2,pre2,suf2,mnpre2,mxpre2,mnsuf2,mxsuf2);
    		ans=1ll*(mxsuf2[1]-mnsuf2[1]+1)*(mxsuf1[1]-mnsuf1[1]+1);
    //		cout<<ans<<endl;
    		FOR(i,0,n1) ans=min(ans,1ll*(mxsuf2[1]-mnsuf2[1]+1)*(
    		min(
    		max(mxsuf1[i+1],suf1[i+1]+1+max(mxpre1[i],0))-min(mnsuf1[i+1],suf1[i+1]+1+min(mnpre1[i],0)),
    		max(mxsuf1[i+1],suf1[i+1]-1+max(mxpre1[i],0))-min(mnsuf1[i+1],suf1[i+1]-1+min(mnpre1[i],0))
    		)+1));
    //		cout<<ans<<endl;
    		FOR(i,0,n2) ans=min(ans,1ll*(mxsuf1[1]-mnsuf1[1]+1)*(
    		min(
    		max(mxsuf2[i+1],suf2[i+1]+1+max(mxpre2[i],0))-min(mnsuf2[i+1],suf2[i+1]+1+min(mnpre2[i],0)),
    		max(mxsuf2[i+1],suf2[i+1]-1+max(mxpre2[i],0))-min(mnsuf2[i+1],suf2[i+1]-1+min(mnpre2[i],0))
    		)+1));
    		cout<<ans<<endl;
    		FOR(i,0,n+1) pre1[i]=suf1[i]=pre2[i]=suf2[i]=mxpre1[i]=mnpre1[i]=mxsuf1[i]=mnsuf1[i]=mxpre2[i]=mnpre2[i]=mxsuf2[i]=mnsuf2[i]=0;
    	}
    }
    

    D

    考虑只有一个 (7) 能不能做。(7) 明显在最右边。对于每个 (1),求出它右边有 (x_i)(3),答案就是 (sumfrac{x_i(x_i-1)}{2})

    然后每次选一个尽可能大的 (x_i),不停构造,由于 (x_i) 肯定不超过 (50000),而且无论 (n) 多小都可以在后面加 (2)(3) 使得 (n) 减少 (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 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 int read(){
        int x=0,f=0;char ch=getchar();
        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;
    }
    int t,n,a[maxn],k;
    int main(){
    	t=read();
    	while(t--){
    		n=read();k=0;MEM(a,0); 
    		while(n){
    			a[++k]=sqrt(2*n);
    			while(a[k]*(a[k]-1)<=2*n) a[k]++;
    			while(a[k]*(a[k]-1)>2*n) a[k]--;
    			n-=a[k]*(a[k]-1)/2;
    		}
    		FOR(i,1,k){
    			printf("1");
    			FOR(j,1,a[i]-a[i+1]) printf("3");
    		}
    		printf("7
    ");
    	}
    }
    

    E

    最小清新的一道题。

    考虑求出 (a[i]) 表示在 (t) 中能以 (i) 结尾匹配的串的个数,(b[i]) 表示在 (t) 中能以 (i) 开头匹配的串的个数。答案是 (sum a[i]b[i+1])

    这两个东西都可以通过 AC 自动机简单求。大概就是维护 fail 链上末尾节点的个数之类的。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=200020,mod=998244353;
    #define MP make_pair
    #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 int read(){
        int x=0,f=0;char ch=getchar();
        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;
    }
    struct ACAM{
    	int cnt,ch[maxn][26],fail[maxn],q[maxn],sum[maxn],h,r,val[maxn];
    	void insert(char *s,int l){
    		int now=0;
    		FOR(i,1,l){
    			int p=s[i]-'a';
    			if(!ch[now][p]) ch[now][p]=++cnt;
    			now=ch[now][p];
    		}
    		sum[now]++;
    	}
    	void build(){
    		h=1;r=0;
    		FOR(i,0,25) if(ch[0][i]) q[++r]=ch[0][i];
    		while(h<=r){
    			int u=q[h++];
    			FOR(i,0,25) if(ch[u][i]){
    				fail[ch[u][i]]=ch[fail[u]][i];
    				sum[ch[u][i]]+=sum[fail[ch[u][i]]];
    				q[++r]=ch[u][i];
    			}
    			else ch[u][i]=ch[fail[u]][i];
    		}
    	}
    	void run(char *s,int l){
    		int now=0;
    		FOR(i,1,l){
    			int p=s[i]-'a';
    			now=ch[now][p];
    			val[i]=sum[now];
    		}
    	}
    }AC[2];
    int n,l;
    ll ans;
    char t[maxn],s[maxn];
    int main(){
    	scanf("%s",t+1);l=strlen(t+1);
    	n=read();
    	FOR(i,1,n){
    		scanf("%s",s+1);
    		int len=strlen(s+1);
    		AC[0].insert(s,len);
    		for(int j=1,k=len;j<k;j++,k--) swap(s[j],s[k]);
    		AC[1].insert(s,len);
    	}
    	AC[0].build();AC[1].build();
    	AC[0].run(t,l);
    	for(int i=1,j=l;i<j;i++,j--) swap(t[i],t[j]);
    	AC[1].run(t,l);
    	FOR(i,1,l) ans+=1ll*AC[0].val[i]*AC[1].val[l-i];
    //	FOR(i,1,l) printf("val1[%d]=%d,val2[%d]=%d
    ",i,AC[0].val[i],i,AC[1].val[l-i+1]);
    	cout<<ans<<endl;
    }
    
  • 相关阅读:
    SQL 两张结构一样的表合并查询 .
    如何引用传递String Boolean 等,并改变他们的值
    SQL数据库还原时备份集中的数据库备份与现有的数据库不同的解决办法
    sqlserver查询指定树形结构的所有子节点
    TortoiseSVN 合并操作简明教程
    svn的merge使用例子
    svn merge部分的详细说明
    SVN使用方法总结
    spring中的aware接口
    spring是怎样面向接口编程的?
  • 原文地址:https://www.cnblogs.com/1000Suns/p/11324211.html
Copyright © 2020-2023  润新知