zoukankan      html  css  js  c++  java
  • 校内NOIP模拟简要题解

    校内NOIP模拟简要题解

     7.15

    T1

    简要题意 : 给定一个N*M的矩阵(N,M小于1018),有多少种方案可以使得每行每列乘积都为K,K为1或-1

    Solution : 在有解的情况下,显然最后一行和最后一列一定可以调整前面的值为K,所以答案为 2(n-1)(m-1)

    显然无解当且仅当N,M不同奇偶,此时答案为0

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline long long read()
    {
        long long f = 1 , x = 0;
        char ch;
        do
        {
            ch = getchar();
            if(ch == '-') f = -1; 
        }while(ch < '0' || ch > '9');
        do
        {
            x = (x<<3) + (x<<1) + ch - '0';
            ch = getchar();
        }while(ch >= '0' && ch <= '9');
        return f*x;
    } 
    
    const int MOD = 1e9 + 7;
    
    long long n,m;
    long long k;
    
    inline long long Pow(long long a, long long b)
    {
        long long ans = 1 ,mul = a;
        while(b)
        {
            if(b&1) ans = (ans * mul) % MOD;
            mul = (mul * mul) % MOD;
            b >>= 1;
        }
        return ans % MOD;
    }
    
    int main()
    {
        freopen("field.in","r",stdin);
        freopen("field.out","w",stdout);
        n = read(),m = read();k = read();
        if((n+m)&1&&k==-1) cout << 0 << endl;
        else printf("%lld
    ",Pow(Pow(2,n-1),m-1)%MOD);
        return 0;
    }
    /* 
    2 1 1
    2 2 2
    2 3 4
    */
    View Code

    T2

    简要题意:

     Solution:显然对于初始值大于i的,往前移一个值就会减一,同理可以考虑小于i的,然后记录一下什么时候大小关系发生改变,模拟一下即可

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline long long read()
    {
        long long f = 1 , x = 0;
        char ch;
        do
        {
            ch = getchar();
            if(ch == '-') f = -1; 
        }while(ch < '0' || ch > '9');
        do
        {
            x = (x<<3) + (x<<1) + ch - '0';
            ch = getchar();
        }while(ch >= '0' && ch <= '9');
        return f*x;
    } 
    
    const int MOD = 1e9 + 7;
    const int MAXN = 1e6 + 10;
    
    int n;
    int p[MAXN];
    int a[MAXN];
    
    int main()
    {
        freopen("mister.in","r",stdin);
        freopen("mister.out","w",stdout);
        n = read();
        long long res = 0;
        long long ans = 0;
        int a1=0,a2=0;
        for(int i = 1; i<=n;i++)
        {
            p[i] = read();
            res += abs(p[i] - i);
            a[(p[i]-i+n)%n]++;
            if(p[i]>i) a1++;
            else a2++;
        }
        ans = res;
        for(int i=1;i<n;i++)
        {
            res += (a2 - a1 - 1);
            res += (p[n-i+1] - 1) - (n - p[n-i+1]);
            a1 = a1 - a[i] + 1;
            a2 = a2 + a[i] - 1;
            if(res < ans)
            {
                ans = res;
            }
        }
        cout << ans << endl;
    }
    /* 
    2 1 1
    2 2 2
    2 3 4
    */
    View Code

    T3

    简要题意:给定一个序列,求出这个序列所有连续子区间最大值减最小值差值的和

    Solution:显然只需要考虑一个数作为最大值和最小值出现的次数即可

    维护第i个数左边第一个大于,小于它的数的位置,和右边第一个大于小于它的数的位置即可

    代码找不到了

    7.16

    T1

    不大会

    T2

    依旧不大会

    T3

    简单期望DP

    先贴个代码

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline long long read()
    {
        long long f = 1,x = 0;
        char ch;
        do
        {
            ch = getchar();
            if(ch == '-') f = -1;
        }while(ch<'0'||ch>'9');
        do
        {
            x = (x<<3) + (x<<1) + ch - '0';
            ch = getchar();    
        }while(ch>='0'&&ch<='9');
        return f*x;    
    } 
    
    #define Rg register 
    
    const int MAXN = 500 + 10;
    const int MOD = 1e9 + 7;
    
    long long n,m,k;
    long long a[MAXN];
    long long f[MAXN][MAXN];
    long long sum[MAXN][MAXN];
    
    inline long long Pow(long long a ,long long b)
    {
        long long ans = 1, mul = a;
        while(b)
        {
            if(b&1) ans = (ans * mul) % MOD;
            mul = mul * mul % MOD;
            b>>=1;
        }
        return ans % MOD;
    }
    
    int main()
    {
        freopen("kat.in","r",stdin);
        freopen("kat.out","w",stdout);
        n = read(),m = read(),k = read();
        for(Rg int i=1;i<=m;i++) a[i] = read();
        // cout << Pow(m,MOD-2) << endl;
        for(Rg int i=1;i<=m;i++) f[1][i] = Pow(m , MOD-2);
        for(Rg int i=1;i<=m;i++) sum[1][i] = (sum[1][i-1]+f[1][i])%MOD; 
        for(Rg int i=2;i<=k;i++)
        {
            for(Rg int j=1;j<=m;j++)
            {
                f[i][j] = (sum[i-1][j-1] + f[i-1][j]*j%MOD) * Pow(m,MOD-2) % MOD;
                // cout << "f:" << f[i][j] << endl;
                sum[i][j] = (sum[i][j-1] + f[i][j]) % MOD;
            }
        }
        long long ans = 0;
        for(Rg int i=1;i<=m;i++) ans = (ans + f[k][i] * a[i])% MOD;
        printf("%lld
    ",ans*(n-k+1)%MOD);
    } 
    View Code

    7.17

    T1

    简要题意 :求1到N的序列中逆序对对数为K的一共有多少个,N,K<=1000

    Solution:考虑到如果是在1-N-1的序列中加入一个N则一定不会有末尾为N的逆序对

    于是考虑 $ f_{i,j} $ 表示加入到了第i个数有j个逆序对的方案数,显然DP即可,可以前缀和优化

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline int read()
    {
        int f = 1,x = 0;
        char ch;
        do
        {
            ch = getchar();
            if(ch == '-') f = -1;
        }while(ch < '0' || ch > '9');
        do
        {
            x = (x<<3) + (x<<1) + ch - '0';
            ch = getchar();
        }while(ch >= '0' && ch <= '9');
        return f*x;
    }
    
    const int MOD = 10000;
    const int MAXN = 2000 + 10;
    
    int T;
    int n,k;
    long long f[MAXN][MAXN]; 
    
    inline void init()
    {
        f[1][0] = 1;
        for(int i=2;i<=1000 + 5;i++)
        {
            long long res = 0;
            for(int j=0;j<=min(1000 + 5,i*(i-1)/2);j++)
            {
                res = (res + f[i-1][j]) % MOD;
                if(j>=i) res -= f[i-1][j-i],res=(res+MOD)%MOD;
                f[i][j] = res % MOD;
            }
        }
    }
    
    int main()
    {
        freopen("permut.in","r",stdin);
        freopen("permut.out","w",stdout);
        T = read();
        init();
        while(T--)
        {
            n = read();k = read();
            printf("%d
    ",f[n][k]);
        } 
    }
    View Code

    T2

    简要题意:

     Solution:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline int read()
    {
        int f = 1,x = 0;
        char ch;
        do
        {
            ch = getchar();
            if(ch == '-') f = -1;
        }while(ch < '0' || ch > '9');
        do
        {
            x = (x<<3) + (x<<1) + ch - '0';
            ch = getchar();
        }while(ch >= '0' && ch <= '9');
        return f*x;
    }
    
    const int MAXN = 2000 + 10;
    
    int n,q;
    int a[MAXN];
    int l[MAXN<<1],r[MAXN<<1];
    int f[MAXN];
    int dp[MAXN][MAXN];
    
    int main()
    {
        freopen("beautiful.in","r",stdin);
        freopen("beautiful.out","w",stdout);
        n = read();
        for(int i=1;i<=n;i++) a[i] = read();
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=2*n;j++) l[j] =r[j] = -1;
            l[n] = r[n] = 0;
            int res = 0;
            for(int j=i-1;j>=1;j--) 
            {
                if(a[j]<=a[i]) res--;
                if(a[j]>a[i]) res++;
                l[n+res] = i - j;
            }
            res = 0;
            for(int j=i+1;j<=n;j++)
            {
                if(a[j]>=a[i]) res++;
                if(a[j]<a[i]) res--;
                r[n+res] = j - i;
            }
            for(int j=1-i;j<=i-1;j++)
            {
                if(r[n+j]>=0&&l[n-j]>=0)
                {
                    f[i] = max(f[i],r[n+j]+l[n-j]+1);    
                }
            }
        }
        for(int i=1;i<=n;i++) dp[i][i] = f[i];
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                dp[i][j] = max(dp[i][j-1],f[j]);
        q = read();
        for(int i=1;i<=q;i++)
        {
            int l = read(),r = read();
            printf("%d
    ",dp[l][r]);
        }
    }
    View Code

    T3

     Solution:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline int read()
    {
        int f = 1,x = 0;
        char ch;
        do
        {
            ch = getchar();
            if(ch == '-') f = -1;
        }while(ch < '0' || ch > '9');
        do
        {
            x = (x<<3) + (x<<1) + ch - '0';
            ch = getchar();
        }while(ch >= '0' && ch <= '9');
        return f*x;
    }
    
    #define Rg register
    #define MAXN 500
    #define pre(x) x>>8
    #define suf(x) x&255
    
    int N;
    int a[MAXN + 10][MAXN + 10];
    char opt[50];
    
    int main()
    {
        freopen("subset.in","r",stdin);
        freopen("subset.out","w",stdout); 
        N = read();
        for(Rg int i=1;i<=N;i++)
        {
            scanf("%s",opt+1);
            int x = read();
            int val;
            if(opt[1]=='d') val=-1;
            else val = 1;
            if(opt[1]=='a'||opt[1]=='d')
            {
                int u = pre(x), v = suf(x) , w = v^255;
                a[u][v] += val;
                for(int S=w;S;S=(S-1)&w) a[u][S|v] += val; // S|v -> father 
            } 
            else
            {
                int u = pre(x) ,v = suf(x);
                long long ans = 0;
                ans += a[0][v];
                for(int S=u;S;S=(S-1)&u) ans += a[S][v];// S -> u son
                printf("%lld
    ",ans);
            }
        }
    } 
    View Code

    10.30

    T1

    简要题意:

    给定一个有向图,对其中一条边u,v,求u,v不经过该边的最短路
    solution:
    每次枚举起点,可以O(M)计算最短路和次短路
     

    T3

    给定一个位数小于1000的数N,重排每位数字,使凑出一个最大的被11整除的数

    solution:

    11的倍数的数满足奇数位和偶数位和相等

    对于一个给定的N,可以直接算出奇数位和和偶数位和

    贪心的考虑可以想到从大到小放入奇数位和偶数位,如果放不到奇数位就一点在偶数位

    所以DP预处理出每种状态的可行性

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline int read()
    {
        int f = 1 ,x = 0;
        char ch;
        do
        {
            ch = getchar();
            if(ch == '-') f = -1;
        }while(ch < '0'||ch > '9');
        do
        {
            x = (x<<3) + (x<<1) + ch - '0';
            ch = getchar();
        }while(ch >= '0'&&ch <= '9');
        return f*x;
    }
    
    const int MAXN = 1000 + 10;
    
    char s[MAXN];
    int x[MAXN];
    int dp[MAXN][MAXN][11];
    int P[MAXN];
    bool vis[MAXN];
    int col[MAXN],coll;
    vector<int>G[2];
    int top[2];
    
    int main()
    {
        freopen("sort.in","r",stdin);
        freopen("sort.out","w",stdout);
        scanf("%s",s+1);
        int len = strlen(s+1);
        int sum = 0;
        for(int i=1;i<=len;i++) x[i] = s[i] - '0',sum = (sum  + x[i]) % 11;
    //    P[0] = 1;for(int i=1;i<=len;i++) P[i] = (P[i-1] * 10) % 11;
        sum %= 11;
        sort(x+1,x+len+1);
        int res = (len+1)/2;
        memset(dp,0,sizeof(dp));
        dp[0][0][0] = 1;
        for(int i=1;i<=len;i++)
        {
            //cout << x[i] << endl;
            for(int j=0;j<=min(res,i);j++)
            {
                for(int k=0;k<=10;k++)
                {
                //    if(i <= 2) cout << i << " " << j << " " << dp[1][0][10] << endl;
                    if(j > 0) dp[i][j][k] = dp[i][j][k]|dp[i-1][j-1][(k-x[i]+11)%11];
                    dp[i][j][k] = dp[i][j][k]|dp[i-1][j][k];
                }
            }
        }
        if(sum & 1) sum += 11;
        int cur = sum / 2;coll = 1;
    //    cout << cur << endl;
        int sum_o = 0,sum_e = 0;
        int cur_o = 0,cur_e = 0;
    //    cout << cur << endl;
        int res_o = res,res_e = len/2;
    //    cout << dp[len-1][res_o-1][(cur - x[len] + 11) % 11] << endl;
        for(int i=len;i>=1;i--)
        {
            if(coll == 1)
            {
                if(res_o < cur_o + 1)
                {
                    while(i>=1) col[i] = 0,i--;
                    continue;
                }
                while(res_o>=cur_o+1&&i>=1&&dp[i-1][res_o-cur_o - 1][(cur - sum_o + 11 -x[i]+11)%11] == 0) sum_e += x[i],sum_e %= 11,cur_e++,col[i] = 0,i--;
                if(!i) break;
            //    cout << i << endl;
                col[i] = 1;sum_o += x[i];sum_o %= 11;cur_o++;coll^=1;
            }
            else
            {
                if(res_e < cur_e + 1)
                {
                    while(i>=1) col[i] = 1,i--;
                    continue;
                }
            //    cout << i-1 << " " << res_e - 1 << " " << (cur - x[i] + 11) % 11 << endl;
            //    return 0;
            //    cout << dp[i-1][res_e-cur_e - 1][(cur - sum_e + 11-x[i]+11)%11] << endl;
                while(res_e>=cur_e+1&&i>=1&&dp[i-1][res_e-cur_e - 1][(cur - sum_e + 11-x[i]+11)%11] == 0) sum_o += x[i],cur_o++,col[i] = 1,i--,sum_o %= 11;
                if(!i) break;
                col[i] = 0;sum_e += x[i];sum_e %= 11;cur_e++;coll^=1;            
            }
        }
        //cout << res_e << " " <<res_o << endl;
    //    cout << 1 << endl;
        for(int i=len;i>=1;i--) G[col[i]].push_back(i);
    //    cout << 1 << endl;
        int curr = 1;
        for(int i=1;i<=len;i++)
        {
            printf("%d",x[G[curr][top[curr]++]]);
            curr^=1;
        }
    //    for(int i=len;i>=1;i--) if(vis[i]) printf("%d",x[i]);
    //    for(int i=len;i>=1;i--) if(!vis[i]) printf("%d",x[i]);
    }
    
     
    View Code
  • 相关阅读:
    基本数据类型(二)
    jquery 基础
    CSS 基础
    Hyperledger Fabric Ordering Service过程
    Hyperledger Fabric Transaction Proposal过程
    Hyperledger Chaincode启动过程
    Hyperledger Fabric1.0 整体结构
    golang学习
    数字签名详解
    设置MongoDB课程环境
  • 原文地址:https://www.cnblogs.com/wlzs1432/p/13829014.html
Copyright © 2011-2022 走看看