zoukankan      html  css  js  c++  java
  • 杂题训练之十

    分析:

    考虑固定左端点L,枚举它

    剩下的任务就是找到最小的R,使之[L,R]能够出现B的子序列

    这样n-R+1也就满足,ans累加

    代码是反着来的,效果是一样的

    学到了

    code by std

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    long long ans,f[105];
    char s[100005],c[105];
    int main(){
    	scanf("%d%d%s%s",&n,&m,s+1,c+1);
    	for(int i=1;i<=n;++i){
    		for(int j=m;j;--j){
    			if(s[i]!=c[j]) continue;
    			if(j==1) f[1]=i;
    			else f[j]=f[j-1];
    		}
    		ans+=f[m];
    	}
    	printf("%lld",ans);
    	return 0;
    }
    

    分析:

    博弈论先考虑终止状态:(切记不要死循环的想)

    先手只剩一条边时,先手必败

    后手只剩两条边时,先手必胜

    然后发现本题唯一和博弈论沾边的就是度数的奇偶性(关键是找对立面)

    1是奇数,扩展开去就是,先手面临奇数的时候一定是必败的

    为什么?因为奇数删了一条边会变成偶数,后手就又删去一条边使得它又变成奇数

    而如果先手面临的是偶数,那么再怎么都不会遇到最后为1的情况

    此时后手就会想尽办法让你的状态变为奇数,可是他无能为力啊

    code by std:

    #include <cstdio>
    
    int n, D[1000010];
    
    int main() {
    	scanf("%d", &n);
    	for (int i = 1, u, v; i < n; ++i) {
    		scanf("%d%d", &u, &v); ++D[u], ++D[v];
    	}
    	for (int i = 1; i <= n; ++i)
    		if (!(D[i] & 1)) { puts("Alice"); return 0; }
    	puts("Bob"); return 0;
    }
    
    

    吐槽:

    为什么过了大样例却wa了

    分析:

    此题的关键在于考虑每个元素的贡献,而不是考虑一个区间的贡献

    code by std:

    #include<bits/stdc++.h>
    const int N=100001,p=1000000007;
    int n,k,a[N],b[N],ans;
    std::unordered_map<int,int>m;
    int main(){
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;++i){
            scanf("%d",&a[i]);
            b[i]=i-m[a[i]];
            m[a[i]]=i;
            ans=(ans+(1LL*n*k%p-i+1+p)%p*b[i])%p;
        }
        for(int i=1;i<=n;++i){
            if(b[i]==i)b[i]+=n-m[a[i]];
            ans=(ans+(500000004LL*(k-1)%p*k%p*n%p-1LL*(k-1)*(i-1)%p+p)%p*b[i])%p;
        }
        printf("%d",ans);
    }
    

    题解:

    分析:本题的关键在如何判断两条路径不会相交

    还有就是可以不用差分,直接容斥一下就好

    code by std:

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int N=3005;
    int n,p,q,cnte,head[N];
    LL f[N][N],g[N][N],fp[N],fq[N],gp[N],gq[N],sump,sumq;
    LL ans;
    struct edge{int to,nxt;}e[N<<1];
    void Add(int a,int b){
        e[++cnte]=(edge){b,head[a]};
        head[a]=cnte;
    }
    void dfs1(int x,int fa){
        f[x][0]=1;
        for(int i=head[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa)continue;
            dfs1(y,x);
            for(int j=1;j<=p;++j)fp[x]+=f[x][p-j]*f[y][j-1];
            for(int j=1;j<=q;++j)fq[x]+=f[x][q-j]*f[y][j-1];
            for(int j=1;j<=p;++j)f[x][j]+=f[y][j-1];
        }
    }
    void dfs2(int x,int fa){
        for(int j=1;j<=p;++j)gp[x]+=f[x][p-j]*g[x][j];
        for(int j=1;j<=q;++j)gq[x]+=f[x][q-j]*g[x][j];
        for(int i=head[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa)continue;
            g[y][1]=1;
            for(int j=2;j<=p;++j)g[y][j]+=g[x][j-1]+f[x][j-1]-f[y][j-2];
            dfs2(y,x);
        }
    }
    int main(){
        scanf("%d%d%d",&n,&p,&q);if(p<q)swap(p,q);
        for(int i=1,a,b;i<n;++i){
            scanf("%d%d",&a,&b);
            Add(a,b);Add(b,a);
        }
        dfs1(1,0);dfs2(1,0);
        for(int i=1;i<=n;++i){sump+=fp[i];sumq+=fq[i];}
        ans=sump*sumq;
        for(int i=1;i<=n;++i)ans-=fp[i]*fq[i]+fp[i]*gq[i]+fq[i]*gp[i];
        printf("%lld",ans<<2);
        return 0;
    }
    
  • 相关阅读:
    线程与进程
    Java集合框架体系JCF
    Java异常
    抽象,接口和Object类
    Java三大特性
    面向对象
    数组
    Java 控制结构与方法
    数据类型与变量
    Java基础之入门
  • 原文地址:https://www.cnblogs.com/wzxbeliever/p/11809037.html
Copyright © 2011-2022 走看看