zoukankan      html  css  js  c++  java
  • hihoCoder #1033 : 交错和 (数位Dp)

    题目大意:

    给定一个数 x,设它十进制展从高位到低位上的数位依次是 a0, a1, ..., an - 1,定义交错和函数:

    f(x) = a0 - a1 + a2 - ... + ( - 1)n - 1an - 1

    例如:

    f(3214567) = 3 - 2 + 1 - 4 + 5 - 6 + 7 = 4

    给定 

    1405402477702.png

    输入

    输入数据仅一行包含三个整数,l, r, k(0 ≤ l ≤ r ≤ 1018, |k| ≤ 100)。

    输出

    输出一行一个整数表示结果,考虑到答案可能很大,输出结果模 109 + 7。

    提示

    对于样例 ,满足条件的数有 110 和 121,所以结果是 231 = 110 + 121。

    更多样例:

    Input
    4344 3214567 3
    Output
    611668829
    Input
    404491953 1587197241 1
    Output
    323937411
    Input
    60296763086567224 193422344885593844 10
    Output
    608746132
    Input
    100 121 -1
    Output
    120



    样例输入

    100 121 0

    样例输出

    231


    题目分析:定义状态dp(len,x,k)表示长度为len,开头数字为x,交错和为k的所有数之和,num(len,x,k)为上述状态的数的个数。则通过递推即可得到这两个状态组,然后构造答案即可。


    ps:这道题贼恶心。。。每一步加或乘运算后必须取余,否则结果一定错误。

    代码如下:
    # include<iostream>
    # include<cstdio>
    # include<map>
    # include<set>
    # include<queue>
    # include<vector>
    # include<list>
    # include<cstring>
    # include<algorithm>
    using namespace std;
    # define LL long long
    
    const int N=1000000000;
    const int mod=1000000007;
    
    int bit[20];
    LL num[25][10][205];
    LL dp[25][10][205];
    LL base[20];
    
    bool ok(int x)
    {
    	return x>=-100&&x<=100;
    }
    
    void init()
    {
    	base[0]=base[1]=1;
    	for(int i=2;i<=20;++i)
    		base[i]=(base[i-1]*10)%mod;
    	memset(num,0,sizeof(num));
    	memset(dp,0,sizeof(dp));
    	for(int i=0;i<10;++i){
    		num[1][i][i+100]=1;
    		dp[1][i][i+100]=i;
    	}
    	int flag=1;
    	for(int i=1;i<20;++i){
    		flag*=-1;
    		for(int j=0;j<10;++j){
    			for(int k=-100;k<=100;++k){
    				for(int l=0;l<10;++l) if(ok(k+flag*l)){
    					num[i+1][j][k+flag*l+100]+=num[i][j][k+100];
    					num[i+1][j][k+flag*l+100]%=mod;
    					dp[i+1][j][k+flag*l+100]+=((dp[i][j][k+100]*10)%mod+(num[i][j][k+100]*l)%mod)%mod;
    					dp[i+1][j][k+flag*l+100]%=mod;
    				}
    			}
    		}
    	}
    }
    
    LL solve(LL x,int k)
    {
    	if(x<0) return 0ll;
    	LL temp=x;
    	bit[0]=0;
    	while(x>0){
    		bit[++bit[0]]=x%10;
    		x/=10;
    	}
    	LL res=0;
    	for(int i=1;i<bit[0];++i)
    		for(int j=1;j<10;++j){
    			res+=dp[i][j][k+100];
    			res%=mod;
    		}
    	int t=0;
    	int flag=1;
    	LL tt=0ll;
    	for(int i=bit[0];i>=1;--i){
    		int low=(i==bit[0])?1:0;
    		for(int j=low;j<bit[i];++j){
    			LL tres=((tt*num[i][j][(k-t)/flag+100])%mod+dp[i][j][(k-t)/flag+100])%mod;
    			res=(res+tres)%mod;
    		}
    		t+=flag*bit[i];
    		tt=(tt+(bit[i]*base[i])%mod)%mod;
    		flag*=-1;
    	}
    	if(t==k)
    		res=(res+temp)%mod;
    	return res;
    }
    
    int main()
    {
    	init();
    	LL k,l,r;
    	//freopen("in.txt","r",stdin);
    	while(~scanf("%lld%lld%d",&l,&r,&k))
    	{
    		LL a=solve(r,k);
    		LL b=solve(l-1,k);
    		if(a<b) a+=mod;
    		printf("%lld
    ",a-b);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    对类对象使用new时地址分配的情况
    c++堆与栈的简单认识
    多态公有继承
    Cookie & Session & JSP入门
    Response & ServletContext
    Java网络编程篇文章阅读顺序
    URL编程
    UDP网络编程
    TCP网络编程
    InetAddress类的使用
  • 原文地址:https://www.cnblogs.com/20143605--pcx/p/5483792.html
Copyright © 2011-2022 走看看