多校冲刺 noip 11.02

没有改完题就跑过来写题解了(无脸题解)

所以关于今天的题我意识到了一些不足,比如关于容斥的

那么明天的计划就在概率期望后面加一些容斥题(包括反演)

关于时间分配和心态

今天考场上心态崩了半个小时,但是后来调整回来了

刚开始十来分钟机房键盘声就起来了,但是我对第一题没有什么思路

我开始慌了,于是花了十来分钟用来调整心态,但是一个小时之后发现真的不会第一题

直接去看第二题了,发现可以切掉,就切了......

此时心态回复一点点,开始打部分分

十一点的时候都打完了,回来看第一题的正解,最后仍然没有看出来......

T1 按位或

首先关于容斥这件事,我考场上是想到容斥了,还是多步容斥

但是到这里就止步了,因为枚举哪一位是空的的复杂度过于高了

所以我就打了个暴力\(DP\)和子任务三的部分分......我是用矩阵乘实现的,复杂度\(\mathcal{O(t^3logn)}\)

正解就是多步容斥,对于\(t<=100\)的情况我们可以直接枚举所有情况,找到空出来的\(0\),直接找容斥系数

但是你发现这里找的数是\(3\)的倍数,而每一个二进制位\(\mod 3\)要么是\(1\)要么是\(2\)

我们直接看每一种空出来多少位,用\(DP\)计算方案数,最后乘一个组合数就可以啦

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int mod=998244353;
int ksm(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;y>>=1;
    }return ret;
}
int n,t,ans;
int sum[3],f[66][3];
int c[66][66];
int sol(int x){
    int ret=0;
    fo(i,max(0ll,x-sum[2]),min(sum[1],x)){
        memset(f,0,sizeof(f));f[0][0]=1;
        fo(j,1,i)fo(k,0,2){
            f[j][k]=(f[j-1][k]+f[j-1][k-1<0?k+2:k-1])%mod;
        }
        //cout<<f[i][0]<<" "<<f[i][1]<<" "<<f[i][2]<<endl;
        fo(j,i+1,x)fo(k,0,2){
            f[j][k]=(f[j-1][k]+f[j-1][k-2<0?k+1:k-2])%mod;
        }
        //cout<<f[x][0]<<" "<<f[x][1]<<" "<<f[x][2]<<endl;
        ret=(ret+ksm(f[x][0],n)*c[sum[1]][i]%mod*c[sum[2]][x-i]%mod)%mod;
    }
    return ret;
}
signed main(){
    freopen("or.in","r",stdin);
    freopen("or.out","w",stdout);
    scanf("%lld%lld",&n,&t);
    c[0][0]=1;fo(i,1,60){
        c[i][0]=1;
        fo(j,1,i)c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
    }
    fo(i,0,60)if((t>>i)&1)sum[(i&1)?2:1]++;
    fo(i,0,sum[1]+sum[2]){
        if((sum[1]+sum[2]-i)&1)ans=(ans-sol(i)+mod)%mod;
        else ans=(ans+sol(i))%mod;
        //cout<<i<<" "<<sol(i)<<endl;
    }
    printf("%lld",ans);
}

T2 最短路径

这个我直接切了

直接找到所有答案的加和最后除以方案数就好了

方案加和就是每一个边被包含在多少张图中加起来

减去每一张图的直径长度,瞎几把整一下就行了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=2005;
const int M=305;
const int mod=998244353;
int ksm(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;y>>=1;
    }return ret;
}
int n,m,k,ans;
int imp[M],dis[M][M];
bool fi[N];
int to[N*2],nxt[N*2],head[N],rp;
void add_edg(int x,int y){
    to[++rp]=y;
    nxt[rp]=head[x];
    head[x]=rp;
}
int c[N][N];
int dep[N];
void dfs_fi(int x,int f){
    dep[x]=dep[f]+1;
    for(int i=head[x];i;i=nxt[i]){
        if(to[i]==f)continue;
        dfs_fi(to[i],x);
    }
}
int siz[N];
void dfs_se(int x,int f){
    if(fi[x])siz[x]=1;
    for(int i=head[x],y;i;i=nxt[i]){
        y=to[i];
        if(y==f)continue;
        dfs_se(y,x);
        siz[x]+=siz[y];
    }
    ans=(ans+2ll*(c[m][k]-c[siz[x]][k]-c[m-siz[x]][k])+4ll*mod)%mod;
}
signed main(){
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    scanf("%lld%lld%lld",&n,&m,&k);
    c[0][0]=1;
    fo(i,1,n){
        c[i][0]=1;
        fo(j,1,i)c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
    }
    fo(i,1,m)scanf("%lld",&imp[i]),fi[imp[i]]=true;
    fo(i,1,n-1){
        int x,y;scanf("%lld%lld",&x,&y);
        add_edg(x,y);add_edg(y,x);
    }
    fo(i,1,m){
        dfs_fi(imp[i],0);
        fo(j,1,m)dis[i][j]=dep[imp[j]]-dep[imp[i]];
    }
    dfs_se(1,0);
    fo(i,1,m){
        fo(j,i+1,m){
            int sum=0;
            fo(l,1,m){
                if(l==i||l==j)continue;
                if(dis[l][i]<dis[i][j]&&dis[l][j]<dis[i][j])sum++;
                else if(l>i&&dis[l][i]<dis[i][j]&&dis[l][j]<=dis[i][j])sum++;
                else if(l>j&&dis[l][i]<=dis[i][j]&&dis[l][j]<=dis[i][j])sum++;
            }
            ans=(ans-c[sum][k-2]*dis[i][j]%mod+mod)%mod;
        }
    }
    //cout<<ans<<" "<<c[m][k]<<endl;
    ans=ans*ksm(c[m][k],mod-2)%mod;
    printf("%lld",ans);
    return 0;
}

T3 不会

T4 对弈

这个要转化成博弈论来做,仍然是\(NIM\)游戏

看题解吧我只是粘个代码,题解过于长了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=66;
const int M=1e4+5;
const int mod=1e9+7;
int ksm(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;y>>=1;
    }return ret;
}
int n,m,k,ans;
int jc[M],inv[M];
int C(int x,int y){return jc[x]*inv[y]%mod*inv[x-y]%mod;}
int up,f[N][M];
signed main(){
    freopen("chess.in","r",stdin);
    freopen("chess.out","w",stdout);
    scanf("%lld%lld%lld",&n,&k,&m);
    up=log2(n);
    jc[0]=1;fo(i,1,n)jc[i]=jc[i-1]*i%mod;
    inv[0]=1;inv[n]=ksm(jc[n],mod-2);
    fu(i,n-1,1)inv[i]=inv[i+1]*(i+1)%mod;
    f[up+1][0]=1;
    fu(i,up+1,1)for(int l=0;(1<<i-1)*l<=n-k;l+=m+1)
    for(int j=0;j+(1<<i-1)*l<=n-k&&l<=k/2;j++){
        (f[i-1][j+(1<<i-1)*l]+=f[i][j]*C(k/2,l)%mod)%=mod;
    }
    for(int i=0;i<=n-k;i++)ans=(ans+(C(i+k/2-1,k/2-1)-f[0][i]+10*mod)%mod*C(n-i-k/2,k/2)%mod)%mod;
    printf("%lld",ans);
    return 0;
}