牛客小白月赛40

B.跳跳跳(区间 DP)

题意
nn个格子呈环形分布,顺时针方向分别标号为1n1\sim n,其中11nn相邻,每个格子上都有一个正整数a[i]a[i],玩家可以选择一个点作为起点开始跳nn下,第ii次跳跃,玩家只可以选择当前位置左边或右边最近且尚未被跳跃过的位置进行一次跳跃,并获得i×a[p]i\times a[p]的得分,其中pp为第 ii次跳跃的位置。
数据范围

\(1<=n<=2000\)

\(1<=a[i]<=2000\)

输入
3
1 1 1
输出
6
分析

如果一个区间被跳完,一定是区间端点是最后一个到达的

代码
const int N = 4000 + 5;
 
    int n, m, k, _;
    int a[N];
    int dp[N][N];

signed main()
{
    // IOS;
    while(~ sd(n)){
        rep(i, 1, n) sd(a[i]), a[i + n] = a[i];
        m = n;
        n = n * 2;
        rep(i, 1, n) dp[i][i] = a[i];
        for(int len = 2; len <= m; len ++){
            for(int i = 1; i <= n; i ++){
                int j = i + len - 1;
                if(j > n) break;
                dp[i][j] = max(dp[i][j - 1] + a[j] * (j - i + 1), dp[i + 1][j] + a[i] * (j - i + 1));
            }
        }
        int maxx = 0;
        for(int i = 1; i <= n; i ++){
            maxx = max(maxx, dp[i][i + m - 1]);
        }
        pd(maxx);
    }
    // PAUSE;
    return 0;
}



C。数字匹配(暴力)

题意
dddd最近比较喜欢二进制数,她认为对于任意两个正整数x,yxyx,y(x\ne y),当且仅当x,yx,y的二进制非前导零部分最大连续重合位数k≥ k时,x,yx,y是匹配的,比如175175的二进制形式为(10101111)(10101111),472472的二进制形式为(111011000)(111011000),因此175175472472最大连续重合部分为(1011)(1011),故这两个数的最大连续重合位数为44
现在给定一个正整数n(n2000)n(n≤2000)和一个kk,求对于所有x,y(1xyn)x,y(且1≤x<y≤n),满足条件的匹配数
数据范围

\((n≤2000,k≤10)\)

输入
6 2
输出
7
分析

每个数变成二进制数并不会超过 \(10\) 位,直接暴力判断每个数 \(i\)\(j∈([0,i-1])\) 中有几个数可以满足重合 \(k\) 位即可,时间复杂度可以是 \(O(n^2logn)\)

代码
const int N = 2000 + 5;
 
    int n, m, k, _;
    string s[N];
    vector<string> v[N];

string calc(int x)
{
    if(x == 0) return "0";
    string ans = "";
    while(x) ans += ('0' + x % 2), x >>= 1;
    return ans;
}

bool sol(int x, int y)
{
    for(int i = 0; i < v[x].size(); i ++){
        for(int j = 0; j < v[y].size(); j ++){
            if(v[x][i] == v[y][j]) return 1;
        }
    }
    return 0;
}

signed main()
{
    // IOS;
    while(~ sdd(n, k)){
        for(int i = 0; i <= n; i ++){
            s[i] = calc(i);
            for(int j = 0; j + k - 1 < s[i].size(); j ++){
                string ans = "";
                for(int l = 0; l < k; l ++){
                    ans += s[i][j + l];
                }
                v[i].pb(ans);
            }
        }
        int ans = 0;
        for(int i = 1; i <= n; i ++){
            for(int j = 0; j < i; j ++){
                if(sol(i, j)) ans ++; 
            }
        }
        pd(ans);
    }
    // PAUSE;
    return 0;
}



H.来点gcd(数论)

题意
给定一个有 nn个元素的多重集 SS,有 mm个询问,对于每个询问,给出一个整数 xx,问是否能选择 SS 的一个非空子集,满足这个子集的 gcdgcd 等于xx,当集合只有一个数时,设这个集合的 gcdgcd 就等于这个数,gcd(x,y)gcd(x,y)的值为x,yx,y的最大公约数
数据范围

\(1<=n+m<=10^6\)

\(1<=x, a[i]<=n\)

输入
2
7 3
2 2 6 6 2 1 5
3
2
6
7 3
6 3 1 4 6 4 3
7
5
2
输出
NO
YES
YES
NO
NO
YES
分析

如果一个数 \(x\) 可以被一个集合求出来,那么这个集合一定全为 \(x\) 的倍数

\(gcd(a, b)<=min(a,b)\),所以对于每个数 \(x\), 如果它所有的倍数构成一个集合仍凑不出来,那么说明 \(x\) 不存在

代码
const int N = 1e6 + 5;
 
    int n, m, k, _;
    int a[N];
    int d[N];

void clear()
{
    rep(i, 1, n){
        a[i] = d[i] = 0;
    }
}

signed main()
{
    // IOS;
    rush(){
        sdd(n, m);
        rep(i, 1, n){
            a[read()] = 1;
        }
        for(int i = 1; i <= n; i ++){
            for(int j = i; j <= n; j += i){
                if(a[j]){
                    d[i] = __gcd(d[i], j);
                }
            }
        }
        while(m --> 0){
            int x = read();
            if(d[x] == x) puts("YES");
            else puts("NO");
        }
        clear();
    }
    // PAUSE;
    return 0;
}
posted @ 2021-11-09 17:15  Bcoi  阅读(111)  评论(0)    收藏  举报