zoukankan      html  css  js  c++  java
  • HZNU Training 29 for Zhejiang Provincial Competition 2020

    L:

    题意:给定一个n*m的网格,每个初始的网格有一个高度 ,每个a[ i ] 在[ l , r ]的区间里;
    两种操作:
    1,相邻方块高度+1
    2 . 一个方块的高度+2
    求使得若干次操作之后网格所有点到达同一高度的初始网格数量。

    解法:考虑最初的网格有奇数有偶数,通过操作2可以把同为奇数的方格对齐,同为偶数的方格对齐,
    最后剩下的网格必然是若干个高度为奇数,若干个高度为偶数的。模2处理后就变成了一个01矩阵。
    问题转化为一个01矩阵对齐的问题。
    如果1的点为偶数,那么通过操作1一定可以调平衡,0同理

    讨论:

    总方案数为:
    $$
    (l-r+1)^{n*m}
    $$
    n*m为奇数:

    奇数 = 偶数 + 奇数,0,1矩阵里必然有为偶数的点,把偶数按操作1对齐即可。

    答案 = 总方案数。

    n*m为偶数:

    偶数 = 偶数 + 偶数 : 可以调平衡,0向1调整,1向0调整都行。

    偶数 = 奇数 + 奇数 :无法调平衡 。

    答案为 总方案数 - 全为 奇数的情况。

    即:
    $$
    令 x=[l,r]区间里奇数个数,y=[l,r]区间里偶数个数 \所求答案即为:\sum_{i=0}^{n*m}C_{n*m}^ix^i *C_{n*m}^{n*m-i}y^i:::::::::i为偶数\=(x+y)^{n*m}:::::的二项式展开中偶数项\为得到(x+y)^{n*m}中偶数项:\构造二项式:\(x-y)^{n*m}=sum_{i=0}^{n*m}(-1)^{n*m-i}C_{n*m}^ix^i *C_{n*m}^{n*m-i}y^i\当i为奇数时,(x-y)^{n*m}和(x+y)^{n*m}的项相互抵消。\即答案为:frac{(x+y)^{n*m}+(x-y)^{n*m}}{2}\以上:n*m为奇数:(x+y)^{n*m}\n*m为偶数:frac{(x+y)^{n*m}+(x-y)^{n*m}}{2}\
    $$

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<vector>
    using namespace std;
    typedef long long ll;
    const ll MOD=998244353;
    ll quickPower(ll a, ll b,ll m) {   //计算a的b次方
        ll ans = 1;
        ll base = a;
        while (b) {
            if (b & 1) {
                ans *= base;
                ans %= m;
            }
            base *= base;
            base %= m;
            b >>= 1;   //注意是b>>=1 not b>>1
        }
        return ans;
    }
    int main(){
            ll x,y,l,r,n,m;
            scanf("%lld %lld %lld %lld",&n,&m,&l,&r);
            ll t=n*m,d=r-l+1;
            ll ans;
            ll nv2=quickPower(2,MOD-2,MOD)%MOD;
            if(d%2==0)x=y=d/2;
            else if(d%2==1&&l%2==1){
                x=d/2+1;
                y=d/2;
            }
            else if(d%2==1&&l%2==0){
                x=d/2;
                y=d/2+1;
            }
            ll sum=quickPower(d,t,MOD)%MOD;
            if(d==1)ans=1;
            else if(t%2==1)ans=sum;
            else  ans=(quickPower(x+y,t,MOD)%MOD+quickPower(x-y,t,MOD)%MOD)*nv2%MOD;
            ans%=MOD;
            printf("%lld
    ",ans);
    
        // system("pause");
        return 0;
    }
    View Code

    B:

    题意:每个点可以控制与之相邻的点,求选取最小的点,使得所有点覆盖。

    设dp[ i ] [ 0 ] 表示i被父结点覆盖

    dp[ i ] [ 1 ] 表示 i 被自己覆盖

    dp[ i ] [ 2 ] 表示 i 被儿子覆盖

    转移即可。

    // #include<bits/stdc++.h>
    #include<cstdio>
    #include<vector>
    using namespace std;
    #define pb push_back
    typedef long long ll;
    const int inf=1e8;
    const int N=1e5+5;
    vector<int>e[N];
    int dp[N][3];
    int n,ans;
    void dfs(int u,int fa){
        bool flag=0;;int inc=inf;
        dp[u][1]=1;
        for(int i=0;i<e[u].size();i++){
            int v=e[u][i];
            if(v==fa)continue;
            dfs(v,u);
            dp[u][0]+=min(dp[v][1],dp[v][2]);
            dp[u][1]+=min(dp[v][0],min(dp[v][1],dp[v][2]));
             if(dp[v][1]<=dp[v][2]){
                flag=1;
                dp[u][2]+=dp[v][1];
            }
            else {
                dp[u][2]+=dp[v][2];
                inc=min(inc,dp[v][1]-dp[v][2]);
            }
        }
        if(!flag)dp[u][2]+=inc;
    }
    int main(){
        scanf("%d",&n);
        for(int i=1,u,v;i<n;i++){
            scanf("%d %d",&u,&v);
            e[u].pb(v);e[v].pb(u);
        } 
        dfs(1,-1);
        int ans=min(dp[1][1],dp[1][2]);
        printf("%d
    ",ans);
        // system("pause");
        return 0;
    }
    View Code

    E - 往

     UVA - 10766 

    简单生成树计数。

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<cstdio>
    #include<set>
    #include<map>
    #include<vector>
    #include<cstdio>
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const int maxn=3e2+100;
    //ll mod=1;
    ll A[maxn][maxn];
    ll B[maxn][maxn];
    ll determinant(int n){
        ll res=1;
        for(int i=1;i<=n;i++){
            if(!B[i][i]){
                bool flag=false;
                for(int j=i+1;j<=n;j++){
                    if(B[j][i]){
                        flag = true;
                        for(int k=i;k<=n;k++){
                            swap(B[i][k],B[j][k]);
                        }
                        res=-res;
                        break;
                    }
                }
                if(! flag)
                return 0;
            }
            
            for(int j=i+1;j<=n;j ++){
                while(B[j][i]){
                    ll t=B[i][i]/B[j][i];
                    for(int k=i;k<=n;k ++){
                        B[i][k]=B[i][k]-t*B[j][k];
                        swap(B[i][k],B[j][k]);
                    }
                    res=-res;
                }
            }
            res*= B[i][i];
        }
        return res;
    }
    int main(){
        int n, m, k;
        while(~ scanf("%d %d %d", &n, &m, &k)){   
            memset(A,0,sizeof(A));
            memset(B,0,sizeof(B));
            for(int i=1;i<=m;i ++){
                int a,b;
                scanf("%d %d",&a,&b);
                A[a][b]=A[b][a]=1;
            }
            for(int i=1;i<=n;i ++){
                for(int j=1;j<=n;j++){
                    if(i!=j&&!A[i][j]){
                        B[i][i]++;
                        B[i][j]=-1; 
                    }
                }
            }
            n=n-1;
            ll ans=determinant(n); 
            printf("%lld
    ", ans);
        }
        return 0;
    }
    View Code

    F - 后

     CodeForces - 557D 

    给定一张图,求最少加多少个边,使得图里有奇环,输出方案总数。

    解法:奇环必然与二分图染色有关。

    加边为0:原本有奇环。

    加边为1:选取一个联通块,点数>2,将同色染在一起。

    加边为2:图里全为线段。

    加边为3:没有边。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define pb push_back
    const int N=1e5+5;
    vector<int>e[N];
    ll n,m;
    ll white[N],black[N];
    int color[N],belong[N],num[N];
    bool vis[N];
    bool dfs(int u,int scc){
        num[scc]++;
        belong[u]=scc;vis[u]=1;
        for(int i=0;i<e[u].size();i++){
            int v=e[u][i];
            if(color[v]==color[u]){return 0;}
            if(!color[v]){
                color[v]=3-color[u];
                if(!dfs(v,scc))return 0;
            }
        }
        return 1;
    }
    void init(){
        // memset(vis,0,sizeof vis);
        // memset(color,0,sizeof color);
        for(int i=1;i<=n;i++)
        vis[i]=color[i]=black[i]=white[i]=belong[i]=0;
    }
    int main(){
        scanf("%lld %lld",&n,&m);
        init();
        for(int i=1,u,v;i<=m;i++){
            scanf("%d %d",&u,&v);
            e[u].pb(v);e[v].pb(u);
        }
        if(m==0){ll ans=1ll*n*(n-1)*(n-2)/6;printf("3 %lld
    ",ans);return 0;}
        int SCC=0;
        bool odd=false;
        for(int i=1;i<=n;i++){
            if(vis[i])continue;
            color[i]=1;
            if(dfs(i,++SCC)==0){
                odd=1;
                break;
            }
        }
        // for(int i=1;i<=n;i++)cout<<color[i]<<endl;
        if(odd){printf("0 1
    ");return 0;}
        for(int i=1;i<=n;i++){
            if(color[i]==1)white[belong[i]]++;
            else  black[belong[i]]++;
        }
        int cnt=0;
        ll ans=0;
        for(int i=1;i<=SCC;i++){
            if(num[i]<=2){
                cnt++;
                continue;
            }
            ans+=(white[i]-1)*white[i]*1ll/2+(black[i]-1)*black[i]*1ll/2;
        }
    
        if(cnt==SCC){
            printf("2 %lld
    ",m*(n-2)*1ll);
        }
        else printf("1 %lld
    ",ans);
        // system("pause");
        return 0;
    }
    View Code
  • 相关阅读:
    在C#中实现高性能计时[转]
    序列化(Serializable)的学习
    日常常用英语
    使用javascript灵活控制DIV的位置
    酷我创始人雷鸣:程序员个人成长的四个要素
    String.Format格式说明
    各种类型转换的比较
    学好计算机英语
    AS关键字进行类型转化的优点以及限制
    Spoken English美国人常用的英语口语
  • 原文地址:https://www.cnblogs.com/littlerita/p/12839839.html
Copyright © 2011-2022 走看看