• 数位DP Ⅱ


    本节题目:数位之间和的关系。一般需要多加一维状态f[i][j][k]:表示长度为i,第一位是i,数位和等于k的数列个数

    Seven Segment Display

    题意:每个数字都有一个对应的权值,求l~r(十六进制数)之间所有数的所有数字的权值和
    预处理数组有点麻烦,f[i][j]表示长度为i,第一个数是j的所有数列的数位之和的总和,f[i][j]=f[i-1][0~15]+j*(长度为i-1的数列个数即pow(16,i-1)).
    dp枚举第i位的数字时统计时还要算上last*(长度为i-1的数列的个数pow(16,i-1)).

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=20;
    LL f[N][N];
    int s[]={6,2,5,5,4,5,6,3,7,6,6,5,4,5,5,4};
    int power[20];
    LL dp(LL n){
    	if(n==0) return s[0]*8;
    	vector<int> nums;
    	for(int i=1;i<=8;++i){
    		nums.push_back(n%16);
    		n/=16;
    	}
    	LL res=0,last=0;
    	for(int i=nums.size()-1;i>=0;--i){
    		int x=nums[i];
    		for(int j=0;j<x;++j){
    			res+=f[i+1][j]+power[i]*last;
    		}
    		last+=s[x];
    	}
    	res+=last;
    	return res;
    }
    int main(){
    	power[0]=1;
    	for(int i=1;i<=10;++i) power[i]=power[i-1]*16;
    	int res=0,p=16;
    	for(int i=0;i<16;++i) f[1][i]=s[i],res+=s[i];//cout<<res<<endl;
    	for(int i=2;i<9;++i,p*=16){
    		for(int j=0;j<16;++j){
    			f[i][j]=s[j]*p;
    			for(int k=0;k<16;++k){
    				f[i][j]+=f[i-1][k];
    			}
    		}
    	}
    	res=0;
    	int T;
    	cin>>T;
    	while(T--){
            LL n,m,t=0xFFFFFFFF;
    	    scanf("%lld%llX",&n,&m);
            LL l=m;
            LL r=m+n-1;
            if(r>t)
                cout<<dp(t)+dp(r%(t+1))-(l==0?0:dp(l-1))<<endl;
            else cout<<dp(r)-(l==0?0:dp(l-1))<<endl;
    	}
    	return 0;
    }
    

    1084. 数字游戏 II

    由于科协里最近真的很流行数字游戏。
    某人又命名了一种取模数,这种数字必须满足各位数字之和 mod N 为 0。
    现在大家又要玩游戏了,指定一个整数闭区间 [a.b],问这个区间内有多少个取模数。
    输入格式
    输入包含多组测试数据,每组数据占一行。
    每组数据包含三个整数 a,b,N。
    输出格式
    对于每个测试数据输出一行结果,表示区间内各位数字和 mod N 为 0 的数的个数。
    数据范围
    1≤a,b≤2^31−1,
    1≤N<100
    输入样例:
    1 19 9
    输出样例:
    2

    f[i][j][k] 长度为i 第一位是i 数位和%m等于k。注意(少生孩子)多取模!
    eg:(a-b+c)%c一样可能小于0 ,应该是((a-b)%c+c)%c

    #include<bits/stdc++.h>
    using namespace std;
    const int N=20,M=110;
    int f[N][N][M]; //f[i][j][k] 长度为i 第一位是i 数位和%m等于k
    int mod(int x,int p){
        return (x%p+p)%p;
    }
    void init(int m){
        memset(f,0,sizeof f);
        for(int i=0;i<10;++i) f[1][i][i%m]++;
        for(int i=2;i<N;++i){
            for(int j=0;j<10;++j){
                for(int k=0;k<10;++k){
                    for(int r=0;r<m;++r){
                        f[i][j][r]+=f[i-1][k][mod(r-j,m)];
                    }
                }
            }
        }
    }
    int dp(int num,int m){
        if(num==0) return 1;
        vector<int> nums;
        while(num) nums.push_back(num%10),num/=10;
        int res=0,last=0;
        for(int i=nums.size()-1;i>=0;--i){
            int x=nums[i];
            for(int j=0;j<x;++j){
                res+=f[i+1][j][mod(m-last,m)];
            }
            last+=x;
            if(i==0&&last%m==0) res++;
        }
        return res;
    }
    int main(){
        int l,r,k;
        while(cin>>l>>r>>k){
            init(k);
            cout<<dp(r,k)-dp(l-1,k)<<endl;
        }
    
    }
    

    1086. 恨7不成妻

    单身!
    依然单身!
    吉哥依然单身!
    DS 级码农吉哥依然单身!
    所以,他平生最恨情人节,不管是 214 还是 77,他都讨厌!
    吉哥观察了 214 和 77 这两个数,发现:
    2+1+4=7
    7+7=7×2
    77=7×11
    最终,他发现原来这一切归根到底都是因为和 7 有关!
    所以,他现在甚至讨厌一切和 7 有关的数!
    什么样的数和 7 有关呢?
    如果一个整数符合下面三个条件之一,那么我们就说这个整数和 7 有关:
    整数中某一位是 7;
    整数的每一位加起来的和是 7 的整数倍;
    这个整数是 7 的整数倍。
    现在问题来了:吉哥想知道在一定区间内和 7 无关的整数的平方和。
    输入格式
    第一行包含整数 T,表示共有 T 组测试数据。
    每组数据占一行,包含两个整数 L 和 R。
    输出格式
    对于每组数据,请计算 [L,R] 中和 7 无关的数字的平方和,并将结果对 109+7 取模后输出。
    数据范围
    1≤T≤50,
    1≤L≤R≤1018
    输入样例:
    3
    1 9
    10 11
    17 17
    输出样例:
    236
    221
    0

    我们要找的数需要满足三个性质,1.不含7 2.数字和%7不等于0 3.数%7不等于0,所以我们的预处理数组需要是个状态f[i][j][a][b]:长度为i,最高位是j,数字之和%7是a,数%7是b。f[i][j][a][b] 由(f[i-1][0,1,2,3,4,5,6,8,9][a-j*10)(i-1)(][b-j])转移得到
    然后这道题问的是所有数的立方和。假设我们枚举到第i位前面last,当前位枚举位j,那么就是立方和就是(jA_1^2+jA_2^2+...+jA_t^2=j×10)i-1(^2×t+2×j×10)(i-1)(×(A_1+A_2+...+A_t)+(A_1^2+A_2^2+...+A_t^2))
    所以需要维护三个值,即(t=s0=A_1^0+A_2^0+...+A_t^0),(s1=A_1^1+A_2^1+...+A_t^1),(s2=A_1^2+A_2^2+...+A_t^2)
    (s0)直接统计个数即可求,(s1=jA_1+jA_2+...+jA_t=j×10)(i-1)(×t+(A_1^1+A_2^1+...+A_t^1))
    注意(少生孩子)多取模!

    #include<bits/stdc++.h>
    using namespace std;
    const int N=21;
    const int P=1e9+7;
    #define int long long
    typedef long long LL;
    struct F{
        int s0,s1,s2;
    }f[N][N][N][N];
    int mod(int x,int y){
        return (x%y+y)%y;
    }
    int power7[N],power9[N];
    void init(){
        for(int i=0;i<10;++i){
                if(i==7) continue;
                auto& v =f[1][i][i%7][i%7];
                v.s0++;v.s1+=i;v.s2+=i*i%P;
                v.s0%=P;v.s1%=P;v.s2%=P;
        }
        LL power=10;
        for(int i=2;i<N;++i,power*=10){
            for(int j=0;j<10;++j){
                if(j==7) continue;
                for(int a=0;a<7;++a){
                    for(int b=0;b<7;++b){
                        for(int k=0;k<10;++k){
                            if(k==7) continue;
                            auto& v1=f[i][j][a][b],v2=f[i-1][k][mod(a-j*power,7)][mod(b-j,7)];
                            v1.s0=mod(v1.s0+v2.s0,P);
                            v1.s1=mod(v1.s1+(v2.s1+j*(power%P)%P*v2.s0%P)%P,P);
                            v1.s2= mod(v1.s2+(j*j%P*(power%P)%P*(power%P)%P*v2.s0%P
                                +2*j*(power%P)%P*v2.s1%P
                                +v2.s2),P);
                        }
                    }
                }
            }
        }
        power7[0]=power9[0]=1;
        for(int i=1;i<N;++i){
            power7[i]=power7[i-1]*10%7;
            power9[i]=power9[i-1]*10%P;
        }
    }
    F get(int i,int j,int a,int b){
        int ss0,ss1,ss2; ss0=ss1=ss2=0;
        for(int aa=0;aa<7;++aa){
            for(int bb=0;bb<7;++bb){
                if(aa==a||bb==b) continue;
                ss0+=f[i][j][aa][bb].s0;ss0%=P;
                ss1+=f[i][j][aa][bb].s1;ss1%=P;
                ss2+=f[i][j][aa][bb].s2;ss2%=P;
            }
        }//cout<<i<<" "<<j<<" "<<a<<" "<<b<<" "<<" "<<s0<<" "<<s1<<" "<<s2<<endl;
        return (F){ss0,ss1,ss2};
    }
    signed dp(LL t){
        if(t==0) return 0;
        LL tt=t;
        vector<int> nums;
        while(tt) nums.push_back(tt%10),tt/=10;
        LL last_a=0,last_b=0,res=0;
        for(int i=nums.size()-1;i>=0;--i){
            int x=nums[i];
            for(int j=0;j<x;++j){
                if(j==7) continue;
                int a=mod(-last_a*power7[i+1],7),b=mod(-last_b,7);
                auto it=get(i+1,j,a,b);
                int s0=it.s0,s1=it.s1,s2=it.s2;
               // cout<<1+i<<" "<<j<<" "<<a<<" "<<b<<" "<<s0<<" "<<s1<<" "<<s2<<" "<<power9[i+1]<<" "<<last_a<<endl;
                res=mod(res+((last_a%P)*(power9[i+1]%P)%P*(last_a%P)%P*(power9[i+1]%P)%P*s0%P
                    +2*(last_a%P)*(power9[i+1]%P)%P*s1%P
                    +s2),P);
            }
    
            if(x==7) break;
            last_a=last_a*10+x;
            last_b+=x;
            if(i==0&&last_b%7&&last_a%7) res=mod(res+((t%P)*(t%P))%P,P);//cout<<t<<" "<<res<<endl;
        }
        return res%P;
    }
    signed main(){
        init();
        int T;
        cin>>T;
        while(T--){
            int a,b;
            cin>>a>>b;
            cout<<mod(dp(b)-dp(a-1),P)<<endl;
        }
        return 0;
    }
    
  • 相关阅读:
    程序员必须知道的10大基础实用算法及其讲解
    6 Java Exceptions that Haunts a Newbie Java Developer(Java菜鸟6种常见的异常)
    在线学习Java免费资源推荐(来自:importnew)
    Oracle触发器
    Oracle性能分析工具介绍及使用
    开口大数据闭口高并发,你们都是怎么回答
    Http中Get/Post请求区别
    快速排序算法
    MAG EF查询增加指定索引功能
    WEB传参
  • 原文地址:https://www.cnblogs.com/jjl0229/p/12660497.html
Copyright © 2020-2023  润新知