2019牛客暑期多校训练营(第五场)

2019牛客暑期多校训练营(第五场)

题号 标题 已通过代码 题解/讨论 通过率 团队的状态
A digits 2 点击查看 进入讨论 1016/2378 通过
B generator 1 点击查看 进入讨论 513/3524 通过
C generator 2 点击查看 进入讨论 34/592 已补
D generator 3 点击查看 进入讨论 4/23 未通过
E independent set 1 点击查看 进入讨论 36/98 队友已补
F maximum clique 1 点击查看 进入讨论 77/779 队友已补
G subsequence 1 点击查看 进入讨论 494/2432 通过
H subsequence 2 点击查看 进入讨论 278/1311 通过
I three points 1 点击查看 进入讨论 125/2614 未通过
J three points 2 点击查看 进入讨论 4/70 队友已补

lwqtql:https://www.cnblogs.com/lwqq3/

zgtql:http://brotherzhi.com/

A

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

B

矩阵快速幂

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod;
 
struct node {
    ll c[2][2];
};
 
node mul(node x, node y) {
    node res;
    memset(res.c, 0, sizeof(res.c));
 
    for(int i = 0; i < 2; i++)
    for(int j = 0; j < 2; j++)
    for(int k = 0; k < 2; k++)
        res.c[i][j] = (res.c[i][j] + x.c[i][k] * y.c[k][j] % mod) % mod;
    return res;
}
 
node pow_mod(node x, ll y) {
    node res;
    res.c[0][0] = res.c[1][1] = 1LL;
    res.c[0][1] = res.c[1][0] = 0LL;
 
    while(y) {
        if(y & 1) res = mul(res, x);
        x = mul(x, x);
        y >>= 1;
    }
    return res;
}
 
char s[1000005];
int ss[1000005];
int main() {
    ll x0, x1, a, b;
    cin>>x0>>x1>>a>>b;
    scanf("%s", s + 1);
    int len = strlen(s + 1);
    for(int i = 1; i <= len; i++) ss[i] = s[i] - '0';
    cin>>mod;
 
    node A;
    A.c[0][0] = a;
    A.c[0][1] = b;
    A.c[1][0] = 1LL;
    A.c[1][1] = 0LL;
    if(len == 1) {
        if(s[1] == '1') {
            printf("%lld
", x1);
            return 0;
        }
    }
    ss[len]--;
    for(int i = len; i >= 1; i--) {
        if(ss[i] < 0) {
            ss[i] += 10;
            ss[i - 1]--;
        }
    }
 
 
    node now;
    now.c[0][0] = now.c[1][1] = 1LL; now.c[0][1] = now.c[1][0] = 0LL;
    for(int i = 1; i <= len; i++) {
        now = pow_mod(now, 10);
        int t = ss[i];
 
        node pp = pow_mod(A, 1LL * t);
        now = mul(now, pp);
    }
    ll ans = now.c[0][0] * x1 % mod + now.c[0][1] * x0 % mod;
    ans %= mod;
    printf("%lld
", ans);
    return 0;
}

C

写了篇题解https://www.cnblogs.com/1625--H/p/11291238.html

BSGS

E

位元状压DP

#include <bits/stdc++.h>
using namespace std;
 
char dp[1 << 26];
int adj[30];
 
int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        adj[u] |= (1 << v);
        adj[v] |= (1 << u);
    }
    for(int i = 0; i < n; i++) adj[i] = (~adj[i]), adj[i] ^= (1 << i);
    //puts("??");
    for(int i = 1; i < (1 << n); i++) {
        int t = __builtin_ctz(i);
        dp[i] = max(dp[i - (1 << t)], (char)(dp[i & adj[t]] + 1));
    }
    int ans = 0;
    for(int i = 1; i < (1 << n); i++) ans += dp[i];
    printf("%d
", ans);
    return 0;
}

G

思路跟标程反了。一直没调对,不知道那里出错了。

下面是按照标程思路写的。思路也不是很难,如果按照长度等不等区分开来进行DP的话,就要额外维护一个东西。

#include <bits/stdc++.h>
using namespace std;
const int N = 3030;
const int mod = 998244353;
typedef long long ll;
char s[N],t[N];
int n,m;
ll d[N][N],C[N][N];
void predo(){
    C[0][0] = 1;
    for(int i=1;i<N;i++){
        C[i][0] = 1;
        for(int j=1;j<N;j++)
            C[i][j] = (C[i-1][j] + C[i-1][j-1])%mod;
    }
}
void add(ll &x,ll y){x = (x + y)%mod;}
void DP(){
    for(int i=0;i<=n;i++)d[i][0] = 1;
    for(int i=0;i<=n;i++)if(s[i] == t[1])d[i][1] = 1;
    for(int j=2;j<=m;j++){
        ll sum = 0;
        for(int i=1;i<=n;i++){
            if(s[i] == t[j])
                add(d[i][j],sum);
            add(sum,d[i][j-1]);
        }
    }
}
int main(){
    int tt;scanf("%d",&tt);
    predo();
    while(tt--){
        scanf("%d%d",&n,&m);
        scanf("%s%s",s+1,t+1);
        ll res = 0;
        for(int i=0;i<=n+1;i++)for(int j=0;j<=n+1;j++)d[i][j] = 0;
        DP();
        for(int i=1;i<=n;i++)
            if(s[i]!='0')
                for(int j=m;j<=(n-i);j++)
                    add(res,C[n-i][j]);
        for(int j=m;j>=1;j--){
            ll sum = j == 1;
            for(int i=1;i<=n;i++){
                if(s[i] > t[j])
                    add(res,sum * C[n-i][m-j]);
                if(j>1)add(sum,d[i][j-1]);
            }
        }
        cout<<res<<endl;
    }
    return 0;
}

H

对于每两个字母,都能知道单个字符前面有多少个别类字符,所有的情况加起来后就知道前面总共有多少个字符了。不可能的情况可能出现在

  • 两次输入中,同一类型字母个数不同
  • 总个数不够n个
  • 两个字符位置相同
  • 有地方空着,或者填入了超出n的位置
#include <bits/stdc++.h>
using namespace std;
const int N = 10010;
int num[20][10010];
int tot[20];
int n,m;
char s[N];
char ans[10*N];
int main(){
    scanf("%d%d",&n,&m);
    bool flag = true;
    for(int i=1;i<=m*(m-1)/2;i++){
        char a,b;
        int len;
        cin>>a>>b;scanf("%d",&len);
        if(len == 0){
            getchar();continue;
        }
        scanf("%s",s);
        int cnta = 0,cntb = 0;
        for(int i=0;i<len;i++){
            if(s[i] == a)cnta++,num[a-'a'][cnta] += cntb;
            if(s[i] == b)cntb++,num[b-'a'][cntb] += cnta;
        }
        //判断个数与之前是否一致
        if(tot[a-'a'] == 0){
            tot[a-'a'] = cnta;
        }
        else if(tot[a-'a'] != cnta){
            flag = false;
        }
        if(tot[b-'a'] == 0){
            tot[b-'a'] = cntb;
        }
        else if(tot[b-'a'] != cntb){
            flag  = false;
        }
    }
    for(int i=0;i<m;i++){
        for(int j=1;j<=tot[i];j++){
            //判断是否有重位,或者位置范围超出n
            if(ans[num[i][j] + j-1] != 0 || num[i][j] + j-1 >= n){
                flag = false;break;
            } 
            ans[num[i][j] + j-1] = 'a'+i;
        }  
        if(!flag)break;
    }
    int sum = 0;for(int i=0;i<m;i++)sum += tot[i];
    if(sum != n)flag = false;
    ans[sum] = '';
    if(flag)printf("%s
",ans);
    else printf("-1");
    return 0;
}
原文地址:https://www.cnblogs.com/1625--H/p/11285495.html