tg 12 题解

幸亏是NOIP模拟赛题解还能看懂

T1

是一个叫“摩尔投票法的东西”,适用于众数出现次数大于\(\frac{n}{2}\)的情况
具体见代码

点击查看代码
#include <bits/stdc++.h>
int read(){
    int i=1,j=0;char ch=getchar();
    while(ch>'9'||ch<'0')i=(ch=='-'?-1:1),ch=getchar();
    while(ch<='9'&&ch>='0')j=j*10+ch-48,ch=getchar();
    return i*j;
}
int main(){
    int now=0,cnt=0,n=read();
    for(int i=1,x;i<=n;i++){
        x=read();
        if(!cnt) cnt++,now=x;
        else {if(x==now){cnt++;}else {cnt--;if(!cnt){now=x,cnt=1;}}}
    }std::cout<<now;std::exit(0);
    return 0;
}

T2

先维护一天的期望,最后乘上\(n-k+1\)即可
维护一天期望,先把概率求出来
对于每个\(i\)\(i\)做最大值的次数为\(i^k-{(i-1)}^k\)
可以简单容斥一波:首先每个位可选\(i\)个,共有\(i^k\)种数列,排除最大值不够\(i\)\((i-1)^k\)种即可
总共有\(m^k\)种,除个这再乘上\(w_i\)加和就是期望

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int o=520,mod=1e9+7;
int n,m,k,w[o],ans,f[o][o];
int P(int x,int y,int mo){
    int ans=1;
    while(y){
        if(y&1){
            ans=ans*x%mo;
        }
        y>>=1;
        x=x*x%mo;
    }
    return ans;
}
int read(){
    int i=1,j=0;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        i=(ch=='-'?-1:1);
        ch=getchar();
    }
    while(ch<='9'&&ch>='0'){
        j=j*10+ch-48;
        ch=getchar();
    }
    return i*j;
}
void in(){
    n=read(),m=read(),k=read();
    for(int i=1;i<=m;i++){
        w[i]=read();
    }
}
void work(){
    int ans1=0,ans2=P(m,k,mod);
    for(int i=1;i<=m;i++){
        ans1+=((P(i,k,mod)-P(i-1,k,mod)+mod)%mod*w[i])%mod;
        ans1%=mod;
    }
   // printf("%lld %lld\n",ans1,ans2);
    ans=ans1*(n-k+1)%mod*P(ans2,mod-2,mod)%mod;
}
void out(){
    printf("%lld\n",ans);
}
signed main(){
    in();
    work();
    out();
    return 0;
}

T3

预设型DP
\(f[i][j][k]\)为已经放置\(i\)个数,\(j\)个位置是都有值的,这些位置相加和为\(k\)
那么:
\(f[i+1][j][k]\)是在\(f[i][j][k]\)的基础上,选定的是两个原来均为空的位置,
这样的方案共有\((n-2*i+j)(n-2*i+j-1)\)
\(f[i+1][j+1][k+i+1]\)是在\(f[i][j][k]\)基础上,选定一个位置不为空,另一个位置为空的/加入的两个数位置相同且原来为空的位置
这样的位置总共\(2*(n-2*i+j)*(i-j)+(n-2*i+j)\)
\(2*(n-2*i+j)*(i-j)\)是说一个空另一个有一个数,\(n-2*i+j\)就是全空
\(f[i+1][j+2][k+2*i+2]\)是在\(f[i][j][k]\)基础上,选定加入的位置都不完全空(填入一个数)的位置
这样的位置共\((i-j)(i-j)\)
然后刷表大力取模即可

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
const int o=55,mod=998244353;
int f[o][o][o*o+1],n,k;
int a[o],b[o],ans;
void in(){
    cin>>n>>k;
}
void work(){
    f[0][0][0]=1;
    for(int i=0;i<n;i++){
        for(int j=0;j<=i;j++){
            for(int k=0;k<o*o;k++){
                f[i+1][j][k]+=f[i][j][k]*(n-2*i+j)*(n-2*i+j-1)%mod;
                f[i+1][j][k]%=mod;
                f[i+1][j+1][k+i+1]+=f[i][j][k]*(2*(n-2*i+j)*(i-j)+(n-2*i+j))%mod;
                f[i+1][j+1][k+i+1]%=mod;
                f[i+1][j+2][k+2*i+2]+=f[i][j][k]*(i-j)*(i-j)%mod;
                f[i+1][j+2][k+2*i+2]%=mod;
            }
        }
    }
    for(int i=o*o;i>=k;i--){
        ans+=f[n][n][i];
        ans%=mod;
    }
}
void out(){
    cout<<ans;
}
signed main(){
    in();
    work();
    out();
    return 0;
}

posted @ 2022-07-25 10:23  2K22  阅读(37)  评论(0)    收藏  举报