zoukankan      html  css  js  c++  java
  • 2019牛客暑期多校第五场题解ABGH

    A.digits 2

    传送门

    题意:给你一个n,要求输出一个每一位数字之和能整除n且其本身也能整除n的数。n不超过100,要求的数不超过10000位数。

    题解:直接将n输出n次。

    代码:

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    int main() {
        int T,n;
        for (scanf("%d",&T);T--;) {
            scanf("%d",&n);
            for (int i = 0; i < n; i++) 
                printf("%d",n);
            printf("
    ");
        }
        return 0;
    }
    View Code

    B.generator 1

    传送门

    题意:已知x0,x1,a,b,n,mod,xi = a*xi-1 + b*xi-2,求xn%mod

    题解:矩阵快速幂,把以二为单位倍增改为以十位单位

    代码:

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    #define maxn 2
    const int N = 1e6 + 10;
    struct Matrix {
        ll ma[maxn][maxn];
        Matrix() {
            memset(ma,0, sizeof(ma));
        }
    }A,E;
    char s[N];
    ll mod;
    Matrix mul(Matrix A,Matrix B) {
        Matrix C;
        for(int i=0;i<maxn;i++)
            for(int j=0;j<maxn;j++)
                for(int k=0;k<maxn;k++)
                    C.ma[i][j]=(C.ma[i][j]+(A.ma[i][k]*B.ma[k][j]+mod)%mod)%mod;
        return C;
    }
    Matrix pow_mod() {
        int len = strlen(s);
        for (int i = len - 1; i >= 0; i--) {
            Matrix C = E;
            int a = s[i] - '0';
            for (int j = 1; j <= 9; j++) {
                if (j == a) A = mul(E,A);
                E = mul(E ,C);
            }
        }
        return A;
    }
    int main() {
        scanf("%lld%lld%lld%lld%s%lld",&A.ma[1][0],&A.ma[0][0],&E.ma[0][0],&E.ma[0][1],s,&mod);
        E.ma[1][0] = 1;
        A = pow_mod();
        printf("%lld
    ", A.ma[1][0]);
        return 0;
    }
    View Code

    G.subsequence 1

    传送门

    题意:告诉你两个由数字组成的字符串s,t,问s串中有多少个子序列所表示的数字比t所表示的数字大。(均不含前导0)

    题解:当s的子序列长度比t长时,显然比t大;当子序列长度与t相等时,我们可以通过动态规划来求解。我们用dp[i][j]来表示s串的前i个和t串的前j个相同的方案数。用两层for循环来判断s串的第i为与t串的第j位的大小关系:前i-1个的情况包含在前i个的情况内,所以我们先把dp[i-1][j]赋值给dp[i][j],当s[i] == t[j]时,s串的前i个和t串的前j个相同的方案数还要加上前i-1位和j-1位相同的情况dp[i-1][j-1];当s[i]>t[j]时,前j-1位的选取情况为dp[i-1][j-1],第j位选i,最后m-j个显然在剩下的n-i个字符中任取m-j个都符合。最后我们再加上长度大于t的不包含前导零的子序列个数即可。

    代码:

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N = 3000 + 10;
    const ll mod = 998244353;
    ll c[N][N],dp[N][N];
    char s[N],t[N];
    int main() {
        int T,n,m;
        c[1][1] = c[1][0] = c[0][0] = 1;
        for (int i = 2; i <= 3000; i++) {
            c[i][0] = c[i][i] = 1;
            for (int j = 1; j < i; j++)
                c[i][j] = (c[i-1][j-1]+c[i-1][j])%mod;
        }
        for (scanf("%d",&T);T--;) {
            scanf("%d%d%s%s",&n,&m,s+1,t+1);
            dp[0][0] = 1;
            ll ans = 0;
            for (int i = 1; i <= n; i++) {
                dp[i][0] = 1;
                for (int j = 1; j <= min(m,i); j++) {
                    dp[i][j] = dp[i-1][j];
                    if (s[i] == t[j]) dp[i][j] = (dp[i][j]+dp[i-1][j-1])%mod;
                    else if (s[i] > t[j]) {
                        ans = (ans + c[n-i][m-j] * dp[i-1][j-1]%mod)%mod;
                    }
                }
            }
            for (int i = 1; i <= n; i++) {
                if (s[i] == '0') continue;
                for (int j = m; j <= n-i; j++) 
                    ans = (ans + c[n-i][j])%mod;
            }
            printf("%lld
    ", ans);
        }
        return 0;
    }
    View Code

    H.subsequence 2

    题意:有一个长度为n,由m个不同字符组成的字符串,给你m*(m-1)/2组数据,每组第一行给两个字符,给出这字符串中这两个字符一共有多少个,再按字符在字符串中出现的顺序输出。问是否能找到符合条件的字符串,不能的话输出-1,能的话随便输出一个符合条件的字符串。

    题解:我们可以将这个字符串看成一个图,根据每个字符类型和它是第几个给它一个编号,再根据前后关系建边,最后通过拓扑序得到序列。要注意字符数量不等于n或者得到的拓扑序个数不等于n时输出-1。

    代码:

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N = 1e4 + 10;
    char c[5],s[N],t[N];
    vector<int> V[N*30];
    int num[30],du[N*30];
    int n,m,len;
    bool topo() {
        queue<int> q;
        for (int i = 0; i < 26; i++) 
            if(num[i]>0 && du[i*10001+1] == 0)
                q.push(i*10001+1);
        int cnt = 0;
        while(q.size()){
            int u = q.front();
            q.pop();
            s[cnt++] = (u-1)/10001 + 'a';
            if (cnt > n) return false;
            for (int i = 0; i < V[u].size(); i++) 
                if (--du[V[u][i]] == 0)  q.push(V[u][i]);
        }
        s[cnt] = '';
        if (cnt == n) return true;
        return false;
    }
    int main() {
        scanf("%d%d",&n,&m);
        m = m*(m-1)/2;
        for (int i = 0; i < m; i++) {
            scanf("%s%d",c,&len);
            if (len == 0) continue;
            scanf("%s",t);
            int num0 =  0, num1 = 0,fst = 0, id;
            for (int j = 0; j < len; j++) {
                if (t[j] == c[0]) {
                    num0++;
                    id = (t[j]-'a')*10001 + num0;
                }else {
                    num1++;
                    id = (t[j]-'a')*10001 + num1;
                }
                if (fst) {
                    du[id]++;
                    V[fst].push_back(id);
                }
                fst = id;
            }
            if (!num[c[0]-'a']) num[c[0]-'a'] = num0;
            if (!num[c[1]-'a']) num[c[1]-'a'] = num1;
        }
        int all = 0;
        for (int i = 0; i < 26; i++) all += num[i];
        if (all != n) printf("-1
    ");
        else if (topo()) printf("%s
    ", s);
        else printf("-1
    ");
        return 0;
    }
    View Code
  • 相关阅读:
    const,var,let区别(转载)
    在windows上搭建redis集群
    Linux学习笔记—vim程序编辑器
    Linux学习笔记—文件与文件系统的压缩与打包(转载)
    Linux学习笔记—Linux磁盘与文件系统管理(转载)
    五,mysql优化——sql语句优化小技巧
    八,mysql优化——读写分离
    六,mysql优化——小知识点
    七,mysql优化——表的垂直划分和水平划分
    三,mysql优化--sql语句优化之索引一
  • 原文地址:https://www.cnblogs.com/l999q/p/11290578.html
Copyright © 2011-2022 走看看