杂题训练之十

Posted wzxbeliever

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了杂题训练之十相关的知识,希望对你有一定的参考价值。

技术图片

分析:

考虑固定左端点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;
}

以上是关于杂题训练之十的主要内容,如果未能解决你的问题,请参考以下文章

杂题训练之四

杂题训练之二

杂题训练之二

作业十代码

codeforces 杂题训练

杂题之循环移动字符串