zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    一对一关联映射
    hibernate 中的 lazy=”proxy” 和 lazy=”no-proxy” 的区别
    Hibernate 延迟加载和立即加载
    hibernate inverse属性的作用
    Hibernate一对多关联
    Hibernate双向多对多关联
    SQL编程
    XML(DOM解析)
    UDP模式聊天
    Thread对象的yield(),wait(),notify(),notifyall()
  • 原文地址:https://www.cnblogs.com/1000Suns/p/11324211.html
Copyright © 2011-2022 走看看