HDU 4507 吉哥系列故事——恨7不成妻 数位DP

来源:互联网 发布:淘宝店铺无线端网址 编辑:程序博客网 时间:2024/05/18 06:23
吉哥系列故事——恨7不成妻
Time Limit: 1000/500 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 746    Accepted Submission(s): 227

Problem Description
  单身!
  依然单身!
  吉哥依然单身!
  DS级码农吉哥依然单身!
  所以,他生平最恨情人节,不管是214还是77,他都讨厌!
  
  吉哥观察了214和77这两个数,发现:
  2+1+4=7
  7+7=7*2
  77=7*11
  最终,他发现原来这一切归根到底都是因为和7有关!所以,他现在甚至讨厌一切和7有关的数!


  什么样的数和7有关呢?


  如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关——
  1、整数中某一位是7;
  2、整数的每一位加起来的和是7的整数倍;
  3、这个整数是7的整数倍;


  现在问题来了:吉哥想知道在一定区间内和7无关的数字的平方和。
 

Input
输入数据的第一行是case数T(1 <= T <= 50),然后接下来的T行表示T个case;每个case在一行内包含两个正整数L, R(1 <= L <= R <= 10^18)。
 

Output
请计算[L,R]中和7无关的数字的平方和,并将结果对10^9 + 7 求模后输出。
 

Sample Input
3 1 9 10 11 17 17
 

Sample Output
236 221 0
 

Source
2013腾讯编程马拉松初赛第一场(3月21日)
 

Recommend
liuyiding
 

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4507


如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关——
  1、整数中某一位是7;
  2、整数的每一位加起来的和是7的整数倍;
  3、这个整数是7的整数倍;


要求一个区间中和7无关的数的平方和。


需要用数位DP维护3个值:


1.与7无关的数的个数


2.与7无关的数的和


3、与7无关的数的平方和。



第一个是与7无关的数的个数,就是简单的数位DP了,很常规。


第二个与7无关的数的和的维护需要用到第一个个数。


处理到第pos个数位时,加上i*10^pos * 后面的个数


第三个的维护需要用到前面两个


(pre*10^pos + next)^2= (pre*10^pos)^2+2*pre*10^pos*next +next^2

个人感觉以下题解易懂:

先来看简单的情况,如果是求和,应该怎么搞。

假如我现在搜索到第3位,一共有5位,情况应该是这样的XXiXX,注意后面的X和前面的X都是不确定的,转移的时候应该是i * 10^(5-3) * (能满足的条件的数的数量) + sigma((每个分支下面满足条件的数量)* (分支和))这样的形式,然后再返回到上一层。这样子就可以记忆化了。但是除了要统计数量,还要统计和。

那么这里要统计平方和的话,如果还是上面这种情况,根据(a + b)^2 = a^2 + 2*a*b + b^2可以得出(i * 10^(5 - 3))^2 * (能满足的条件的数的数量) + 2 * sigma((每个分支下面满足条件的数量)*(分支和)) + sigma(分支平方和)。所以出了要维护分支和,还要维护分支平方和和数量。


打个比方,1   2  3  4  5  6  8  9  10  11  12  13  14  15   18   19   20   21....都满足条件

那么 11^2=(10+1)^2=10^2+2*10*1+1^2

12^2=(10+2)^2=10^2+2*10*2+2^2

13^2=10^2+2*10*3+3^2

.......

11^2+12^2+13^2+....=10^2*(2,3,4,5...这些组合上10满足不成7的数的个数)+2*10*(1+2+3+...这些组合上10满足不成7的数(其实也就是当前位前一个状态所统计数的和))+其实也就是当前位前一个状态所统计数的平方和,因此,“个数”,“和”,“平方和” 是三个必须统计的量,递归出

也就是说十位数是一的这些数的平方和等于 (求和)(10+X)^2=10^2*f(X)+2*10*(qiu求和f(X))+(求和)(f(X)^2)     

f(X)当满足条件时是有的,不满足条件是0




#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <stack>
using namespace std;
typedef long long ll;
#define PI 3.1415926535897932
#define E 2.718281828459045
#define INF 0x3f3f3f3f
#define mod 1000000007


const int M=1005;
int n,m;
int cnt;
int sx,sy,sz;
int mp[1000][1000];
int pa[M*10],rankk[M];
int head[M*6],vis[M*100];
int dis[M*100];
ll prime[M*1000];
bool isprime[M*1000];
int lowcost[M],closet[M];
char st1[5050],st2[5050];
int len[M*6];
typedef pair<int ,int> ac;
//vector<int> g[M*10];


int has[10500];
int month[13]= {0,31,59,90,120,151,181,212,243,273,304,334,0};
int dir[8][2]= {{0,1},{0,-1},{-1,0},{1,0},{1,1},{1,-1},{-1,1},{-1,-1}};


void getpri()
{
    ll i;
    int j;
    cnt=0;
    memset(isprime,false,sizeof(isprime));
    for(i=2; i<1000000LL; i++)
    {
        if(!isprime[i])prime[cnt++]=i;
        for(j=0; j<cnt&&prime[j]*i<1000000LL; j++)
        {
            isprime[i*prime[j]]=1;
            if(i%prime[j]==0)break;
        }
    }
}
struct node
{
    int v,w;
    node(int vv,int ww)
    {
        v=vv;
        w=ww;
    }
};
vector<int> g[M*100];
string str[1000];
struct op
{
    ll cnt;//与7无关的数的个数
    ll sum;//与7无关的数的和
    ll pfsum;//平方和
} dp[20][10][10][2];
//int dp[20][200000];
int bit[50];
ll p[30];
op dfs(int cur,int presum,int num,int s,int e,int z)
{
    //if(s<0)return 0;//不能光相信模板,这么实际的情况都米想到
    if(cur<0)
    {
        op tmp;
        tmp.cnt=(presum&&num&&!s);
        tmp.sum=tmp.pfsum=0;
        return tmp;
    }
    if(!e&&!z&&dp[cur][presum][num][s].cnt!=-1)
        return dp[cur][presum][num][s];
    int endx=e?bit[cur]:9;
    //int ans=0;
    op tmp,ans;
    ans.cnt=ans.sum=ans.pfsum=0;
    for(int i=0; i<=endx; i++)
    {
        //if(i==7)continue;
        if(z&&!i) tmp=dfs(cur-1,(presum+i)%7,(num*10+i)%7,s||i==7,e&&i==endx,1);
        else tmp=dfs(cur-1,(presum+i)%7,(num*10+i)%7,s||i==7,e&&i==endx,0);
        //ans+=dfs(cur-1,get_news(s,i),e&&i==endx,0);
        ans.cnt=(ans.cnt+tmp.cnt)%mod;
        ans.sum=(ans.sum+(tmp.sum+(p[cur]*i)%mod*tmp.cnt%mod)%mod)%mod;


        ans.pfsum+=(tmp.pfsum+((2*p[cur]*i)%mod)*tmp.sum)%mod;//ans+=2*a*b+分支平方和
        ans.pfsum%=mod;
        ans.pfsum+=((tmp.cnt*p[cur])%mod*p[cur]%mod*i*i%mod);
        ans.pfsum%=mod;
    }
    if(!e&&!z) dp[cur][presum][num][s]=ans;
    return ans;
}


ll solve(ll x)
{
    int len=0;
    while(x)
    {
        bit[len++]=x%10;
        x/=10;
    }
    return dfs(len-1,0,0,0,1,1).pfsum;
}
int main()
{
    int i,j,k,t;
    ll l,r;
    scanf("%d",&t);
    p[0]=1;
    for(i=1;i<20;i++)p[i]=(p[i-1]*10)%mod;//注意取模!!
    for( i=0;i<20;i++)
        for( j=0;j<10;j++)
            for( k=0;k<10;k++)
                dp[i][j][k][0].cnt=dp[i][j][k][1].cnt=-1;
    while(t--)
    {
        scanf("%I64d%I64d",&l,&r);
        printf("%I64d\n",((solve(r)-solve(l-1))%mod+mod)%mod);
    }
    return 0;
}


推荐博客:http://blog.csdn.net/cillyb/article/details/55833081
kb大神代码:

/*
 *  如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关——
  1、整数中某一位是7;
  2、整数的每一位加起来的和是7的整数倍;
  3、这个整数是7的整数倍;


求一个区间中与7无关的数的平方和
 */
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const long long MOD=1000000007LL;
struct Node
{
    long long cnt;//与7无关的数的个数
    long long sum;//与7无关的数的和
    long long sqsum;//平方和
}dp[20][10][10];//分别是处理的数位、数字和%7,数%7
int bit[20];
long long p[20];//p[i]=10^i


Node dfs(int pos,int pre1,int pre2,bool flag)
{
    if(pos==-1)
    {
        Node tmp;
        tmp.cnt=(pre1!=0 && pre2!=0);
        tmp.sum=tmp.sqsum=0;
        return tmp;
    }
    if(!flag && dp[pos][pre1][pre2].cnt!=-1)
        return dp[pos][pre1][pre2];
    int end=flag?bit[pos]:9;
    Node ans;
    Node tmp;
    ans.cnt=ans.sqsum=ans.sum=0;
    for(int i=0;i<=end;i++)
    {
        if(i==7)continue;
        tmp=dfs(pos-1,(pre1+i)%7,(pre2*10+i)%7,flag&&i==end);
        ans.cnt+=tmp.cnt;
        ans.cnt%=MOD;
        ans.sum+=(tmp.sum+ ((p[pos]*i)%MOD)*tmp.cnt%MOD )%MOD;
        ans.sum%=MOD;


        ans.sqsum+=(tmp.sqsum + ( (2*p[pos]*i)%MOD )*tmp.sum)%MOD;
        ans.sqsum%=MOD;
        ans.sqsum+=( (tmp.cnt*p[pos])%MOD*p[pos]%MOD*i*i%MOD );
        ans.sqsum%=MOD;
    }
    if(!flag)dp[pos][pre1][pre2]=ans;
    return ans;
}
long long calc(long long n)
{
    int pos=0;
    while(n)
    {
        bit[pos++]=n%10;
        n/=10;
    }
    return dfs(pos-1,0,0,1).sqsum;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
    long long l,r;
    p[0]=1;
    for(int i=1;i<20;i++)
        p[i]=(p[i-1]*10)%MOD;
    for(int i=0;i<20;i++)
        for(int j=0;j<10;j++)
            for(int k=0;k<10;k++)
                dp[i][j][k].cnt=-1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%I64d%I64d",&l,&r);
        long long ans=calc(r);
        ans-=calc(l-1);
        ans=(ans%MOD+MOD)%MOD;
        printf("%I64d\n",ans);
    }
    return 0;
}

0 0
原创粉丝点击