现在的位置: 首页 > 综合 > 正文

hdu 4722 Good Numbers 2013 ACM/ICPC Asia Regional Online —— Warmup2

2018年01月14日 ⁄ 综合 ⁄ 共 1872字 ⁄ 字号 评论关闭

蒟蒻只能想通简单题== 刷OJ太容易让人自我嫌弃了==

dp[i][j]表示i位的数,MOD10=k的个数。

预处理里面,是从低往高递推,包含的是0~9..9(i位)的整个范围的个数。

状态转移时,从高位往低位转移,并用pre记录i位前面(更高位)的各位数之和,因为每一位的数是枚举上界,在之前的枚举不会达到。

举个例子,2753

i=4: 0~1 [3位数0~999中%10=k的个数]

i=3: 2 0~6 [2位数0~99中%10=k的个数]

i=2:270~4 [1位数0~9中%10=k的个数]

i=1: 2750~2 [0位数中%10=k的个数]

这里的枚举不会到达2753,所以最后是solve(b+1)-solve(a)

然后初始状态dp[0][0]=1;我也不是很清楚为什么这样,不过举个例子可以看出,对于2而言,dp[1][0]=dp[0][k],只能算1个(只有0符合条件),如果dp[0][i]=1 for all i,会算多了.

Plus,这里面按位数枚举是disjoint sample space,所以最后的ans要相加,而且ans只能在循环内相加,因为只有这里面的状态转移是合法的。

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<stdlib.h>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<queue>
#include <ctype.h>
#include<map>
#include<time.h>
using namespace std;
//hdu 4722

int T;
long long A;
long long B;
long long dp[20][10];
int digit[20];
int len;
void initial()
{
    memset(dp,0,sizeof(dp));
    dp[0][0]=1;
    for(int i=0;i<=9;i++)
    {
        dp[1][i]=1;
    }
    for(int i=2;i<=19;i++)
    {
        for(int j=0;j<=9;j++)
        {
            for(int k=0;k<=9;k++)
            {
                dp[i][(j+k)%10]+=dp[i-1][k];
            }
        }
    }
}
void toarray(long long a)
{
    len=0;
    memset(digit,0,sizeof(digit));
    while(a)
    {
        digit[++len]=a%10;
        a=a/10;
    }
}
long long solve(int len)
{
    int pre=0;
    long long ans=0;
    //cout<<len<<endl;
    for(int i=len;i>0;i--)
    {
        for(int x=0;x<digit[i];x++)
        {
            for(int k=0;k<=9;k++)
            {
               // dp[i][(pre+x+k)%10]+=dp[i-1][k]; 感觉不要相加,不过加了没影响,因为循环到后面不会用到加过的状态
                if((pre+x+k)%10==0)
                {
                    ans+=dp[i-1][k];//所以dp[0][0]=1, when number=1
                    //cout<<pre<<" "<<x<<endl;
                 //   cout<<ans<<" "<<i<<" "<<k<<" "<<dp[i-1][k]<<endl;
                }
            }
        }
        pre=(pre+digit[i])%10;//加上高位的数(之前的枚举上界) 之前写成了pre=(pre+x)%10; debug了半天。。
       // ans+=dp[i][0]; ans不能在最后再加,因为当dp[i][0]没有进入循环时,是不合法的,所以要在循环内累加
    }
    return ans;
}

int main()
{
    freopen("input.txt","r",stdin);
   //  freopen("data.txt","r",stdin);
    // freopen("out1.txt","w",stdout);
    scanf("%d",&T);
    for(int t=1;t<=T;t++)
    {
        scanf("%I64d %I64d",&A,&B);
        initial();
        toarray(A);
        long long a=solve(len);
        initial();
        toarray(B+1);
        long long b=solve(len);
      //  cout<<b<<" "<<a<<endl;
        printf("Case #%d: %I64d\n",t,b-a);
    }

    return 0;
}



抱歉!评论已关闭.