• 18.10.17 考试总结


    今天心态崩崩,,,.。

       

    这道题比较简单 因为每一位是单独对答案产生贡献的 所以枚举每一位 用数位dp求出该位是$1$的数量 在求出该位是$0$的

    那么答案就是那一位对应的二的幂次再乘以$num1 * num0 * 2$ 每一对会产生两次贡献

    代码

    #include <bits/stdc++.h>
    #define rg register
    #define il inline
    using namespace std;
    
    typedef long long ll;
    const ll MOD = 1e9 + 7;
    int T, dig[40], lim;
    ll p[50], dp[40][2][2], L, R, ans;
    
    il ll read( ) {
        
        ll t = 1, ans = 0;
        char x; x = getchar( );
        while(x < '0' || x > '9') {
            if(x == '-') t = -1;
            x = getchar( );
        }
        while(x >= '0' && x <= '9') {
            ans = ans * 10 + x - '0';
            x = getchar( );
        }
        return ans * t;
    }
    
    il void Init( ) {
        
        p[0] = 1;
        for(rg int i = 1;i <= 32;i ++) {
            p[i] = p[i - 1] * 2 % MOD;
        }
    }
    
    il void init(ll a) {
        
        ll b = a; lim = 0;
        while(b) {
            dig[++ lim] = b & 1;
            b >>= 1;
        }
    }
    
    il ll dfs(int dep, int up, ll ans, int pos) {
        
        if(dep == 0) return ans;
        if(~ dp[dep][up][ans]) return dp[dep][up][ans];
        int h = up ? dig[dep] : 1;
        ll tmp = 0;
        for(rg int i = 0;i <= h;i ++) {
            if((dep == pos) && (i == 1)) tmp += dfs(dep - 1, up && (i == h), ans + 1, pos);
            else tmp += dfs(dep - 1, up && (i == h), ans, pos); 
        }
        return dp[dep][up][ans] = tmp;
    }
    
    il ll solve(ll a, ll pos) {
        
        init(a); memset(dp, -1, sizeof(dp));
        return dfs(lim, 1, 0, pos);
    }
    
    il void Solve( ) {
        
        scanf("%d",& T);
        while(T --) {
            ll L, R, l;
            L = read( ), R = read( );
            l = L;
            if(L == 0) l = 1; ans = 0;
            for(rg int i = 0;i <= 31;i ++) {
                ll num1 = solve(R, i + 1) - solve(l - 1, i + 1);
                ll num0 = (R - L + 1 - num1) % MOD;
                ll num = 2 * num1 % MOD * num0 % MOD;
                ans = (ans + p[i] * num % MOD) % MOD;
            }
            printf("%lld
    ", ans);
        }
    }
    
    int main( ) {
    
        freopen("xor.in","r",stdin);
        freopen("xor.out","w",stdout);
        Init( );    
        Solve( );
    }

     

    这道题是一道博弈论的dp 现在用$dp[x][y][z]$数组表示三堆分别是$x,y,z$时他必输还是必胜

    我们可以通过已经求出来的必败态来筛掉必败态 因为若是后继状态中有必败态 那么他就是必胜态 否则是必败态

    若一个确定了一堆的状态为必败态 那么若剩下两堆的差值是固定的 它就可以通过加减到达我现在的状态 那么我现在状态就必胜

    同样的 若我确定了两堆 那么另外一堆不管是什么都可以直接必胜

    最后是三堆 若三堆确定了 那么它们两两差值也就确定了 同样可以确定我现在的状态

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 305;
    int T, p[5];
    bool dp[N][N][N], h[N][N][6];
    
    void Solve( ) {
        
        scanf("%d",& T);
        for(int i = 0;i <= 300;i ++)
            for(int j = 0;j <= i;j ++) {
                for(int k = 0;k <= j;k ++) {
                    bool tag = true;
                    if(h[i][j - k][0]) tag = false;
                    if(h[j][i - k][0]) tag = false;
                    if(h[k][i - j][0]) tag = false;
                    if(h[i][j][1])        tag = false;
                    if(h[j][k][1])     tag = false;
                    if(h[i][k][1])     tag = false;
                    if(h[i - j][j - k][2]) tag = false;
                    if(tag) {
                        dp[i][j][k] = true;
                        h[i][j - k][0] = h[j][i - k][0] = h[k][i - j][0] = h[i][j][1] = h[j][k][1] = h[i][k][1] = h[i - j][j - k][2] = true;
                    }
                }
            }
    }
    
    int main( ) {
        
        freopen("stone.in","r",stdin);
        freopen("stone.out","w",stdout);
        Solve( );
        while(T --) {
            scanf("%d%d%d",& p[0],& p[1],& p[2]);
            sort(p, p + 3);
            if(dp[p[2]][p[1]][p[0]]) printf("No
    ");
            else printf("Yes
    ");
        }
    }

    这道题是一道恶星$dp$呕 这道题首先可以确定这玩意贪心取每一个值

    然后$dp[i][j][k]$表示我到了第$i$个数 我总共分了$j$段当前状态是$0/1/2/3$时候的最优答案

    状态是什么呢 我们考虑拆开绝对值 那么一段数$S$产生的贡献是他的两倍 不产生贡献 或者产生负二倍贡献 

    所以贡献就是$2 0 0 -2$ 这种 并且不可能出现$2 0 0 0 2$这种 因为若他是$2$那么就需要负的去补 然后后面跟着一堆$0$也就是说最后两个盛了两个正的 所以末尾肯定是两个负的去补

    状态$0$表示当前这个点在贡献为正的一段 $1$表示贡献为$0$的一段 并且这一段是跟在贡献为正的后面 $2/3$跟$1$正好相反

    转移 $dp[i][j][0]$由 $dp[i - 1][j][0]/dp[i - 1][j - 1][2/3]$转移来 其余的类似 记住特判第一个和最后一个只产生$1 / -1$的贡献

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 30004;
    int dp[N][205][5], a[N], n, k;
    
    void Init( ) {
        
        scanf("%d%d",& n,& k);
        for(int i = 1;i <= n;i ++) scanf("%d",& a[i]);
    }
    
    void Solve( ) {
        
        memset(dp, 128, sizeof(dp));
        for(int i = 0;i <= n;i ++) dp[i][0][0] = dp[i][0][2] = 0;
        for(int i = 1;i <= n;i ++) {
            for(int j = 1;j <= min(i, k); j ++) {
                int flag = 2 - (j == 1 || j == k);
                dp[i][j][0] = max(dp[i - 1][j - 1][3], max(dp[i - 1][j][0], dp[i - 1][j - 1][2])) + flag * a[i];
                if(j > 1 && j < k) dp[i][j][1] = max(dp[i][j][1], dp[i - 1][j][0]);
                dp[i][j][2] = max(dp[i - 1][j - 1][1], max(dp[i - 1][j][2], dp[i - 1][j - 1][0])) - flag * a[i];
                if(j > 1 && j < k) dp[i][j][3] = max(dp[i - 1][j][3], dp[i - 1][j - 1][2]);
            }
        }
        int ans = 0;
        for(int i = k;i <= n;i ++) ans = max(ans, max(dp[i][k][2], dp[i][k][0]));
        printf("%d
    ", ans);
    }
    
    int main( ) {
        
        freopen("optimization.in","r",stdin);
        freopen("optimization.out","w",stdout);
        Init( );
        Solve( );
    }
  • 相关阅读:
    Telink TLSR825x系列SDK增加串口打印log功能
    Telink BDT和烧录器EVK的使用
    Telink SDK IDE开发环境中函数链接跳转异常和实际编译项目显示灰色问题的解决
    Telink SDK 的编译设置(以825x系列的一个SDK为例)
    Telink IDE的下载和SDK的导入
    Git项目管理出现 .gitignore文件不起作用的解决
    char和signed char不同编译器下的使用反思
    动态内存的分配
    结构体和联合体
    C语言中利用clock设计一个简单的定时器
  • 原文地址:https://www.cnblogs.com/Rubenisveryhandsome/p/9806223.html
Copyright © 2020-2023  润新知