[20180613]校内模拟赛

T1【Atcoder 2021】

  dp。f[i][j]表示前i个小朋友,分j个糖果所计算出来的value。前缀处理1~i的j次幂的和。

  f[0][0]=1

  f[i][j]=sigma(k=0~j)f[i-1][k]*qz[b[i]][j-k]-qz[a[i]-1][j-k]

  然后要注意取模操作。

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
#define mod 1000000007
#define MN 405
long long f[MN][MN],pw[MN][MN],qz[MN][MN];
int n,c,a[MN],b[MN];
void add(long long &x,long long y){x+=y;if(x>mod)x-=mod;}
long long Abs(long long x){if(x<0) x+=mod;return x;}
int main(){
    register int i,j,k;
    for(i=1;i<=400;i++) pw[i][0]=1;
    
    for(i=1;i<=400;i++)for(j=1;j<=400;j++) pw[i][j]=(pw[i][j-1]*i)%mod;
    for(i=1;i<=400;i++)for(j=0;j<=400;j++) qz[i][j]=(qz[i-1][j]+pw[i][j])%mod;
    
    n=read(),c=read();
    for(i=1;i<=n;i++) a[i]=read();
    for(i=1;i<=n;i++) b[i]=read();
    
    f[0][0]=1;
    
    for(i=1;i<=n;i++)for(j=0;j<=c;j++)for(k=j;k>=0;k--){
        add(f[i][j],f[i-1][k]*Abs(qz[b[i]][j-k]-qz[a[i]-1][j-k])%mod);
    }
    printf("%lld\n",f[n][c]);
    return 0;
}

T2:【Atcoder 3911】

  首先,并查集各联通块中的最小点权和。

  显然,处理联通块的个数为(n-m),每连接一条边就要消耗掉2个点,所以如果(n-m-1)*2>n,就puts("Impossible").

  如果n-m=1,答案为0

  我们要选出(n-m-1)*2个点,其中,各联通块的最小点必须被取到,剩下取最小的(n-m-2)个点就行了。证明显然。

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
#define MN 100005
int n,m,fa[MN],vis[MN],cnt,p[MN],ct;
long long a[MN],ans;
int findf(int x){return fa[x]==x?fa[x]:fa[x]=findf(fa[x]);}
void union_(int x,int y){x=findf(x);y=findf(y);fa[x]=y;return;}
vector<int> pic[MN];
int main(){
    n=read(),m=read();
    register int i,j,x,y;
    for(i=1;i<=n;i++) a[i]=read(),fa[i]=i;
    for(i=1;i<=m;i++){
        x=read()+1,y=read()+1;
        union_(x,y);
    }
    if(m==n-1) return puts("0"),0;
    if((n-m-1)*2>n) return puts("Impossible\n"),0;
    for(i=1;i<=n;i++){
        if(vis[findf(i)]) pic[vis[fa[i]]].push_back(a[i]);
        else pic[vis[findf(i)]=++cnt].push_back(a[i]);
    }
    for(i=1;i<=cnt;i++){
        sort(pic[i].begin(),pic[i].end()),ans+=pic[i][0];
        for(j=1;j<pic[i].size();j++) p[++ct]=pic[i][j];
    }
    sort(p+1,p+ct+1);
    for(i=1;i<=n-m-2;i++) ans+=p[i];
    printf("%lld",ans);
    return 0;
}

T3:【Atcoder 3967】

  我们对4n^2个点进行两次染色处理。

  当D为奇数时,显然D只能被分成奇数和偶数的平方和,所以直接将图进行交叉染色,同色的显然距离不会为D。

  当D为偶数时,我们通过旋转图,是相邻点的边为原先的对角线,然后D>>=1,通过不断的旋转,直至D是一个奇数。

  经过不断的画图和总结,我们发现最终图的染色方法为(用01表示),记D中含有2的指数为k,记squ=2^(k>>1)

  如果k为偶数:

             0 0 0 1 1 1 0 0 0 

     0 0 0 1 1 1 0 0 0 

     0 0 0 1 1 1 0 0 0 

     1 1 1 0 0 0 1 1 1

       1 1 1 0 0 0 1 1 1 

            1 1 1 0 0 0 1 1 1

             0 0 0 1 1 1 0 0 0 

     0 0 0 1 1 1 0 0 0 

     0 0 0 1 1 1 0 0 0 

     其中,任意一个纯1或纯0的矩阵边长是squ。

  如果k为奇数:

    0 0 0 0 0 0 0 0 0 

    0 0 0 0 0 0 0 0 0 

    0 0 0 0 0 0 0 0 0

    1 1 1 1 1 1 1 1 1

    1 1 1 1 1 1 1 1 1

    1 1 1 1 1 1 1 1 1

    0 0 0 0 0 0 0 0 0 

    0 0 0 0 0 0 0 0 0 

    0 0 0 0 0 0 0 0 0

  其中,任意一个纯1或纯0的矩阵行数是squ。

  证明的话,多画画图就发现了。

  然后对于一个点,它会有4种染色情况(11,10,00,01),根据4种情况将图分成4个集合。

  根据平均数的性质,4n^2个点分为4个集合,必定有一个集合它的个数大于等于n^2.

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
#define MN 605
pair<int,int> mp[MN<<1];
int N,D1,D2,cc;
bool col[MN][MN][2];
struct node{int x,y;};
vector<node> G[5];
void solve(int D,int l){
    register int i,j,k,ct=0,squ=1;
    while(~D&1){ct++;D>>=1;}
    squ=1<<(ct>>1);
    if(~ct&1){
        for(i=0;i<N*2;i++)for(j=0;j<N*2;j++)col[i][j][l]=((i/squ)+(j/squ))&1;
    }
    else{
        for(i=0;i<N*2;i++)for(j=0;j<N*2;j++) col[i][j][l]=(i/squ)&1;
    }
}
int main(){
    register int i,j;
    N=read(),D1=read(),D2=read();
    solve(D1,0),solve(D2,1);
    for(i=0;i<N<<1;i++)for(j=0;j<N<<1;j++)
    G[col[i][j][0]+col[i][j][1]<<1].push_back((node){i,j});
    for(i=0;i<4;i++)if(G[i].size()>=N*N){
        for(j=0;j<N*N;j++) printf("%d %d\n",G[i][j].x,G[i][j].y);
        return 0;
    }
    return 0;
}

 


   来自PaperCloud的博客,未经允许,请勿转载,TKS!

posted @ 2018-06-14 17:08  PaperCloud  阅读(188)  评论(0编辑  收藏  举报