2020牛客暑期多校训练营(第六场)

2020牛客暑期多校训练营(第六场)

k-bag

题意 :你有一个字符串 a, 字符串a可以分为 x份, 每份长度为 k且只含有 1到k的数字 (随便怎么排)

然后给你字符串b问你,b是字符串a的子串吗?是就是 yes, 不是就是 no。

题解:

要使字符串 b 是a的子串

那么 b的第一份与最后一份 可以随便排, 中间必须每长度k分成一份且每份只含有1到k的数字。

如果第一份的位置确定, 那么 后面的位置也随之确定。

所以枚举 第一份的所有可能的位置, 判断是否有答案。

我们可以用一个 \(le[i]\)表示 第i位数 右边第一个不合法的位置。

代码:

#include<bits/stdc++.h>
using namespace std;
 
const int N = 2e6 + 7;
 
unordered_map<int, int>vis;
 
int le[N], a[N];
 
int main() {
    int t; scanf("%d", &t);
    while (t--) {
 
        vis.clear();
        int n, k; scanf("%d %d", &n, &k);
        int f = 0;
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            if (a[i] > k) {
                f = 1;
            }
        }
        if (f) {
            puts("NO");
        } else if (k >= n) {
            int l = 1;
            while (l <= n && vis[a[l]] == 0) vis[a[l]] = 1, l++;
            vis.clear();
            int r = n;
            while(r <= n && vis[a[r]] == 0) vis[a[r]] = 1, r--;
            if (l > r) {
                puts("YES");
            } else {
                puts("NO");
            }
        } else {
            int l = 1;
            for (int i = 1; i <= n; i++) {
                while (l <= n && vis[a[l]] == 0) {
                    vis[a[l]] = 1;
                    l++;
                }
                le[i] = l;
                vis[a[i]] = 0;
            }
            int flag = 0;
            for (int i = 1; i < le[1]; i++) {
                int ok = 0;
                for (int j = i + 1; j <= n; j += k) {
                    if (le[j] > n) {
                        break;
                    }
                    if (le[j] - j != k) {
                        ok = 1;
                        break;
                    }
                }
                if (ok == 0) {
                    flag = 1;
                    break;
                }
            }
            if (flag) {
                puts("YES");
            } else {
                puts("NO");
            }
             
        }
    }
}

Harmony Pairs

题意:给你一个数字A, 问再 1 到 A中, 有多少对 (x, y)满足 x的数字之和 大于 y的数字之和 且 x \(\le\) y

题解:

dfs 暴力枚举两个数

判断是否合法。

然后加 记忆化。

再dfs里面 相同参数进去出来结果肯定一样,所以加上记忆化会大大减少时间。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int N = 100 + 7;
ll dp[N][2000][2][2][2];
int up[N], n;

const ll mod = 1e9 + 7;

ll dfs(int p, int sum, int f, int f1,int ok) {
   if (p == n) {
       if (ok && sum > 1000) {
           return 1;
       } 
       return 0;
   }
   if (dp[p][sum][f][f1][ok] != -1) return dp[p][sum][f][f1][ok];
   int maxn, maxn1;
   if (f) {
       maxn = up[p];
   } else {
       maxn = 9;
   }
   if (f1) {
       maxn1 = up[p];
   } else {
       maxn1 = 9;
   }
   ll ans = 0;
   for (int i = 0; i <= maxn; i++) {
       for (int j = 0; j <= maxn1; j++) {
            if (!ok && i > j) continue;
            ans = (ans + dfs(p + 1, sum + i - j, f && i == maxn, f1 && j == maxn1, ok | (j > i? 1: 0)));
            ans = ans % mod;
       }
   }
   return dp[p][sum][f][f1][ok] = ans;
    
}

int main() {
    string s;
    cin >> s;
    for (int i = 0; i < s.length(); i++) {
        up[i] = s[i] - '0';
    }
    n = s.length(); 
    memset(dp, -1, sizeof(dp));
    ll ans = dfs(0, 1000, 1, 1, 0);
   
    printf("%lld\n", ans);
    



}


posted @ 2020-07-29 20:11  ccsu_zhaobo  阅读(107)  评论(0)    收藏  举报