zoukankan      html  css  js  c++  java
  • BZOJ 1236: SPOJ1433 KPSUM

    Description

    用+-号连接1-n所有数字的数位,问结果是多少.

    Sol

    数位DP.

    (f[i][j][0/1][0/1]) 表示长度为 (i) 的数字,开头数字是 (j) ,是否有前导0(这个会影响符号),每相邻两组数符号是否相同.

    转移开一下代码吧.

    这道题的符号有点乱,所以转移看起来有些乱...其实只有3个状态,没前导0,有前导0相邻两个数符号相同,有前导0相邻两个数符号不同.

    没前导0的只有在第一次统计才会用到.

    我发现自己写数位DP就是写小于 (n) 的,所有都需要将 (n+1) 计算...

    一开始自己神tm的取了模...

    Code

    /**************************************************************
        Problem: 1236
        User: BeiYu
        Language: C++
        Result: Accepted
        Time:0 ms
        Memory:1308 kb
    ****************************************************************/
     
    #include <cstdio>
    #include <iostream>
    using namespace std;
     
    #define debug(a) cout<<#a<<"="<<a<<" " 
     
    typedef long long LL;
    const int N = 25;
     
    LL n;
    LL f[N][N][2][2];// i,j  0/1 qiandao0 0/1 fuhao
    LL pow10[N];
     
    void init() {
        pow10[0]=1;
        for(int i=1;i<=18;i++) pow10[i]=pow10[i-1]*10;
        for(int j=0;j<10;j++) {
            f[1][j][0][0]=f[1][j-1][0][0]+(j&1 ? 1 : -1)*j;
            f[1][j][1][0]=f[1][j][0][0];
            f[1][j][1][1]=f[1][j-1][1][1]-j;
        }
        for(int i=2;i<=18;i++) {
            f[i][0][0][0]=f[i-1][9][0][0];
            f[i][0][1][0]=-f[i-1][9][1][0];
            f[i][0][1][1]=-f[i-1][9][1][1];
            for(int j=1;j<10;j++) {
                f[i][j][0][0]=f[i][j-1][0][0]-f[i-1][9][1][!(i&1)]-(!(i&1))*j*pow10[i-1];
                f[i][j][1][0]=f[i][j-1][1][0]-f[i-1][9][1][0];
                f[i][j][1][1]=f[i][j-1][1][1]-f[i-1][9][1][1]-j*pow10[i-1];
            }
        }
         
    /*  for(int i=1;i<=3;i++) {
            for(int j=0;j<10;j++) {
                cout<<i<<" "<<j<<":
    ";
                for(int p=0;p<2;p++) for(int q=0;q<2;q++) debug(f[i][j][p][q]);
                cout<<endl;
            }
        }*/
    }
    LL calc(LL x) {
        LL g=0,r=0,v=0;
        for(int i=18;i;i--) {
            if(x/pow10[i-1]) {
                if(!g) {
                    r+=f[i][x/pow10[i-1]-1][0][0];
                    g=i;
                }else {
                    r+=f[i][x/pow10[i-1]-1][1][!(g&1)]*((g-i)&1 ? -1 : 1);
                }
                if(g&1){
                    if((x%pow10[i-1])&1) r+=x/pow10[i-1]*((g-i)&1 ? 1 : -1);
                }else {
                    r+=x/pow10[i-1]*(x%pow10[i-1])*((g-i)&1 ? 1 : -1);
                }
            }x%=pow10[i-1];
        }return r;
    }
    int main() {
        init();
        cin>>n;
        cout<<calc(n+1)<<endl;
    //  while(cin>>n) cout<<calc(n+1)<<endl;
        return 0;
    }
    
  • 相关阅读:
    第一次做Java程序注意事项
    数制学习笔记
    1228作业
    1226作业(转为十进制)
    [SDOI2010] 古代猪文 (快速幂+中国剩余定理+欧拉定理+卢卡斯定理) 解题报告
    Miller-Rabin
    STL整理之set
    [HNOI2008] GT考试(DP+矩阵快速幂+KMP)
    [JZOJ4024] [佛山市选2015] 石子游戏 解题报告
    [JZOJ3383] [NOIP2013模拟] 太鼓达人 解题报告(数位欧拉)
  • 原文地址:https://www.cnblogs.com/beiyuoi/p/6198846.html
Copyright © 2011-2022 走看看