noip模拟51[好IOI]

noip模拟51 solutions

好像是和别的学校一起考得

然后我交错比赛了,变成了\(IOI\)赛制,交上去就是俩\(AC\)

所以这次的题前两个过于水了。。。。

T1 茅山道术

就是找在当前条件下的,序列不重合划分的方案数,直接\(DP\),类似前缀和优化一下

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=1e6+5;
const int mod=1e9+7;
int n,c[N];
vector<int> vec[N];
int dp[N],sum[N],pos[N];
signed main(){
    freopen("magic.in","r",stdin);
    freopen("magic.out","w",stdout);
    scanf("%d",&n);
    for(re i=1;i<=n;i++)scanf("%d",&c[i]);
    n=unique(c+1,c+n+1)-c-1;
    for(re i=1;i<=n;i++)vec[c[i]].push_back(i),pos[i]=vec[c[i]].size()-1;
    dp[0]=0;
    for(re i=1;i<=n;i++){
        dp[i]=dp[i-1];
        if(pos[i])dp[i]=(dp[i]+sum[vec[c[i]][pos[i]-1]-1]+pos[i])%mod;
        if(pos[i])sum[i-1]=(dp[i-1]+sum[vec[c[i]][pos[i]-1]-1])%mod;
        else sum[i-1]=dp[i-1];
        //cout<<dp[i]<<" "<<sum[i-1]<<" "<<sum[vec[c[i]][pos[i]-1]-1]<<" "<<pos[i]<<endl;
    }
    //cout<<endl;
    printf("%d",dp[n]+1);
}

T2 泰拳警告

直接找规律,然后统计答案就好了

枚举平了多少局,后面第一个人必须胜一半以上

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define re register int
const int N=3e6+5;
const int mod=998244353;
int n,p,pf[N],pg[N],jc[N],inv[N],ans,n2,m2[N];
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 C(int x,int y){
    return jc[x]*inv[y]%mod*inv[x-y]%mod;
}
signed main(){
    freopen("fight.in","r",stdin);
    freopen("fight.out","w",stdout);
    scanf("%lld%lld",&n,&p);
    pf[0]=pg[0]=1;n2=ksm(2,mod-2);
    pf[1]=ksm(p+2,mod-2);pg[1]=p*ksm(p+2,mod-2)%mod;
    jc[0]=jc[1]=1;m2[0]=1;m2[1]=2;
    for(re i=2;i<=n;i++){
        pf[i]=pf[i-1]*pf[1]%mod;
        pg[i]=pg[i-1]*pg[1]%mod;
        jc[i]=jc[i-1]*i%mod;
        m2[i]=m2[i-1]*2%mod;
    }
    inv[0]=1;inv[n]=ksm(jc[n],mod-2);
    for(re i=n-1;i>=1;i--)inv[i]=inv[i+1]*(i+1)%mod;
    //cout<<ksm(9,mod-2)<<" "<<ksm(3,mod-2)<<endl;
    for(re i=0;i<=n;i++){
        int tmp;
        if((n-i)&1)tmp=m2[n-i]*n2%mod*C(n,i)%mod;
        else tmp=(m2[n-i]*n2%mod+mod-C(n-i,n-i>>1)*n2%mod)%mod*C(n,i)%mod;
        ans=(ans+pg[i]*pf[n-i]%mod*(i+1)%mod*tmp%mod)%mod;
        //cout<<pf[i]<<" "<<pg[n-i]<<" "<<ans<<endl;
    }
    printf("%lld",ans);
}

T3 万猪拱塔

首先看题要看准,\(k\)是互不相同的

所以我当前矩形的数一定是一个连续的区间

直接枚举这个区间判断是否构成矩形

按着题解上说的,枚举右端点,更新所在的四个小矩形,线段树

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define re register int 
const int N=2e5+5;
const int mod=998244353;
int n,m,ans,rp;
vector<int> jz[N],id[N];
struct position{
    int i,j;
    position(){}
    position(int x,int y){i=x;j=y;}
}ti[N];
struct XDS{
    #define ls x<<1
    #define rs x<<1|1
    int sum[N*4],csm[N*4],res[N*4],tag[N*4];
    int re_csm,re_res;
    void pushup(int x){
        sum[x]=min(sum[ls],sum[rs]);csm[x]=0;res[x]=0;
        if(sum[x]==sum[ls])csm[x]+=csm[ls],res[x]+=res[ls];
        if(sum[x]==sum[rs])csm[x]+=csm[rs],res[x]+=res[rs];
    }
    void pushdown(int x){
        if(!tag[x])return ;
        tag[ls]+=tag[x];
        tag[rs]+=tag[x];
        sum[ls]+=tag[x];sum[rs]+=tag[x];
        tag[x]=0;
    }
    void build(int x,int l,int r){
        if(l==r){
            csm[x]=1;sum[x]=0;res[x]=l;
            return ;
        }
        int mid=l+r>>1;
        build(ls,l,mid);
        build(rs,mid+1,r);
        pushup(x);
        return ;
    }
    void ins(int x,int l,int r,int ql,int qr,int v){
        if(ql>qr)return ;
        if(ql<=l&&r<=qr){
            sum[x]+=v;tag[x]+=v;
            return ;
        }
        pushdown(x);
        int mid=l+r>>1;
        if(ql<=mid)ins(ls,l,mid,ql,qr,v);
        if(qr>mid)ins(rs,mid+1,r,ql,qr,v);
        pushup(x);return ;
    }
    void query(int x,int l,int r,int ql,int qr){
        if(ql<=l&&r<=qr){
            if(sum[x]==4)re_csm+=csm[x],re_res+=res[x];
            return ;
        }
        pushdown(x);
        int mid=l+r>>1;
        if(ql<=mid)query(ls,l,mid,ql,qr);
        if(qr>mid)query(rs,mid+1,r,ql,qr);
        pushup(x);
    }
    #undef ls
    #undef rs
}xds;
int ji[5],cnt;
signed main(){
    freopen("pig.in","r",stdin);
    freopen("pig.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    jz[0].resize(m+5);jz[n+1].resize(m+5);
    for(re i=1;i<=n;i++){
        jz[i].resize(m+5);
        id[i].resize(m+5);
        for(re j=1;j<=m;j++){
            scanf("%lld",&jz[i][j]);
            ti[jz[i][j]]=position(i,j);
        }
    }
    //cout<<"Sb"<<endl;
    xds.build(1,1,n*m);
    for(re i=1;i<=n*m;i++){
        int x=ti[i].i,y=ti[i].j;
        cnt=0;
        if(jz[x-1][y-1]<i)ji[++cnt]=jz[x-1][y-1];
        if(jz[x][y-1]<i)ji[++cnt]=jz[x][y-1];
        if(jz[x-1][y]<i)ji[++cnt]=jz[x-1][y];
        sort(ji+1,ji+cnt+1);
        xds.ins(1,1,n*m,ji[cnt]+1,i,1);
        for(re j=cnt,bas=-1;j>=1;j--)xds.ins(1,1,n*m,ji[j-1]+1,ji[j],bas),bas=-bas;
        cnt=0;
        if(jz[x-1][y+1]<i)ji[++cnt]=jz[x-1][y+1];
        if(jz[x][y+1]<i)ji[++cnt]=jz[x][y+1];
        if(jz[x-1][y]<i)ji[++cnt]=jz[x-1][y];
        sort(ji+1,ji+cnt+1);
        xds.ins(1,1,n*m,ji[cnt]+1,i,1);
        for(re j=cnt,bas=-1;j>=1;j--)xds.ins(1,1,n*m,ji[j-1]+1,ji[j],bas),bas=-bas;
        cnt=0;
        if(jz[x+1][y-1]<i)ji[++cnt]=jz[x+1][y-1];
        if(jz[x][y-1]<i)ji[++cnt]=jz[x][y-1];
        if(jz[x+1][y]<i)ji[++cnt]=jz[x+1][y];
        sort(ji+1,ji+cnt+1);
        xds.ins(1,1,n*m,ji[cnt]+1,i,1);
        for(re j=cnt,bas=-1;j>=1;j--)xds.ins(1,1,n*m,ji[j-1]+1,ji[j],bas),bas=-bas;
        cnt=0;
        if(jz[x+1][y+1]<i)ji[++cnt]=jz[x+1][y+1];
        if(jz[x][y+1]<i)ji[++cnt]=jz[x][y+1];
        if(jz[x+1][y]<i)ji[++cnt]=jz[x+1][y];
        sort(ji+1,ji+cnt+1);
        xds.ins(1,1,n*m,ji[cnt]+1,i,1);
        for(re j=cnt,bas=-1;j>=1;j--)xds.ins(1,1,n*m,ji[j-1]+1,ji[j],bas),bas=-bas;
        xds.re_csm=xds.re_res=0;
        xds.query(1,1,n*m,1,i);
        //cout<<xds.re_res<<" "<<xds.re_csm<<endl;
        (ans+=1ll*i*xds.re_csm-xds.re_res+xds.re_csm)%=mod;
    }
    printf("%lld",ans);
}

T4 抑郁刀法

这个首先要找到20pts的做法,直接状压dp,\(dp[i][j]\)表示\(i\)状态下用了\(j\)个颜色

注意要乘上一个组合数的

然后你发现这个图好像边特别少啊

直接先把1度点干掉,再把2度点干掉

再dp

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10;
const int mod=1e9+7;
int n,m,k,ans=1;
struct EDGE{int to,id;};
vector<EDGE> edg[N];
int du[N],f[N<<1],g[N<<1],p[N];
bool vpot[N],vedg[N<<1],vpof[N],vis[N<<1];
int id[N],rd[N],nn,jc[N],inv[N];
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 C(int x,int y){if(y>x)return 0;return jc[x]*inv[y]%mod*inv[x-y]%mod;}
void del1(){
    queue<int> q;
    for(int i=1;i<=n;i++)if(du[i]==1)q.push(i);
    while(!q.empty()){
        int x=q.front();q.pop();
        vpot[x]=true;ans=ans*(k-1)%mod;
        for(auto i:edg[x]){
            int y=i.to;
            if(vpot[y])continue;
            du[y]--;vedg[i.id]=true;
            if(du[y]==1)q.push(y);
        }
    }
    memset(du,0,sizeof(du));
    for(int i=1;i<=n;i++){
        vector<EDGE> tmp=edg[i];edg[i].clear();
        for(auto j:tmp)if(!vpot[j.to])edg[i].push_back(j),du[i]++;
    }
}
void del2(){
    for(int i=1;i<=n;i++){
        if(du[i]!=2 or vpot[i] or vpof[i])continue;
        int x=edg[i][0].to,ix=edg[i][0].id;
        int y=edg[i][1].to,iy=edg[i][1].id;
        vedg[ix]=vedg[iy]=true;vpot[i]=true;
        int nid=++m;
        f[nid]=(f[ix]*g[iy]%mod+g[ix]*f[iy]%mod+(k-2)*f[ix]%mod*f[iy]%mod)%mod;
        g[nid]=(g[ix]*g[iy]%mod+(k-1)*f[ix]%mod*f[iy]%mod)%mod;
        if(x==y)vpof[x]=true,f[nid]=0;
        for(auto &j:edg[x])if(j.to==i)j=EDGE{y,nid};
        for(auto &j:edg[y])if(j.to==i)j=EDGE{x,nid};
    }
    for(int i=1;i<=n;i++)if(!vpot[i])++nn,id[nn]=i,rd[i]=nn;n=nn;
    for(int i=1;i<=n;i++){
        vector<EDGE> tmp=edg[id[i]];edg[id[i]].clear();
        for(auto j:tmp){
            if(j.to==id[i]){if(!vis[j.id])ans=ans*g[j.id]%mod,vis[j.id]=true;continue;}
            if(!vedg[j.id])edg[id[i]].push_back(j);
        }
    }
}
int dp[1<<12][12],qa[1<<12];
int get(int s,int t){
    int ret=1;
    for(int i=1;i<=n;i++){
        if(!(s&(1<<i-1)))continue;
        for(auto j:edg[id[i]])
            if(t&(1<<rd[j.to]-1))
                ret=ret*f[j.id]%mod;
    }
    return ret;
}
void sol(){
    dp[0][0]=1;int S=(1<<n)-1,res=0;
    for(int i=1;i<=S;i++){qa[i]=1;
        for(int j=1;j<=n;j++){
            if(!(i&(1<<j-1)))continue;
            for(auto k:edg[id[j]]){
                if(rd[k.to]<j||!(i&(1<<rd[k.to]-1)))continue;
                qa[i]=qa[i]*g[k.id]%mod;//cout<<i<<" "<<k.id<<" "<<g[k.id]<<endl;
            }
        }
    }
    for(int i=0;i<=S;i++){
        for(int j=0;j<n;j++){
            //if(!dp[i][j])continue;
            int u=S^i;
            for(int k=u;k;k=(k-1)&u)
                dp[i|k][j+1]=(dp[i|k][j+1]+dp[i][j]*get(i,k)%mod*qa[k])%mod;//cout<<i<<" "<<k<<" "<<j<<" "<<n<<" "<<get(i,k)<<" "<<qa[k]<<endl;
        }
    }
    //cout<<n<<" "<<qa[1]<<endl;
    for(int i=1;i<=n;i++)res=(res+dp[S][i]*C(k,i))%mod;//cout<<S<<" "<<i<<" "<<dp[S][i]<<endl;
    //cout<<res<<endl;
    ans=ans*res%mod;
}
signed main(){
    freopen("knife.in","r",stdin);
    freopen("knife.out","w",stdout);
    scanf("%lld%lld%lld",&n,&m,&k);
    for(int i=1,x,y;i<=m;i++){
        scanf("%lld%lld",&x,&y);
        du[x]++;du[y]++;f[i]=1;
        edg[x].push_back(EDGE{y,i});
        edg[y].push_back(EDGE{x,i});
    }
    jc[0]=1;for(int i=1;i<=k;i++)jc[i]=jc[i-1]*i%mod;
    inv[0]=1;inv[k]=ksm(jc[k],mod-2);
    for(int i=k-1;i>=1;i--)inv[i]=inv[i+1]*(i+1)%mod;
    del1();//cout<<"del1"<<" "<<ans<<endl;
    del2();//cout<<"del2"<<" "<<ans<<endl;
    sol();
    printf("%lld",ans);
}
posted @ 2021-09-15 07:00  fengwu2005  阅读(82)  评论(0编辑  收藏  举报