hihocoder 1033 交错和

[题目连接:][1]

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

给定一个数 x,设它十进制展从高位到低位上的数位依次是 a0, a1, …, an - 1,定义交错和函数:
f(x) = a0 - a1 + a2 - … + ( - 1)^[n - 1]*an - 1 例如:
f(3214567) = 3 - 2 + 1 - 4 + 5 - 6 + 7 = 4 给定 l, r, k,求在 [l, r] 区间中,所有
f(x) = k 的 x 的和,

输入

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

输出

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

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

思路:

憋了好几天才把思路捋顺,并把代码敲出来1A,恨自己思路不够清楚呀,吐槽结束。
看这数据范围,直接计数显然是不科学,很有可能存在重复子问题等待挖掘。考虑到输入是串,串的长度或许是一个序,在串长度增长的时候,进行决策。
定义dp[i][j][k]表示前i位数字串(第i位为最高位),第i位为数字j,交错和为k时的所有可行方案的数的和。dp[i][j][k]=dp[i-1][][k'] + 10^(i-1)*cnt*j
k’ 为k-j(奇数位)或者k+j(偶数位),表示k从k’转移过来。
这里有一个cnt很重要,因为串增加 1 位(高位),总和需要增加10^(i-1)*j,但是前i-1位交错和为k’的总方案数不一定是 1,当有多个方案时,就不止增加一个10^(i-1) * j 了,因此需要增加一个dpcnt[i][j][k]记录当前状态的方案数。

如前3位,第3位为1,k=1,dp[3][1][1],得到100,111,122...等共10种方案。
dp[4][1][0]在考虑dp[3][1][1]时,得到1100,1111,1122,1133等,每个都要增加1000,即dp[4][1][0]增加10*1000*1 + dp[3][1][1]。
在考虑dp[3][2][1]时,也会有多种方案,总方案数必须得记录下来。

到这里问题解决了三分之一,对于[1111,22345]区间,要考虑怎么从已经记录的状态里取出我们要的答案,可以分别左右区间的[0,L],[0,R]答案,然后做减法。注意到是闭区间,将L-1即可。

具体如何取出[0,22345]的答案呢?
我们记录的是各个数位可以[0,9]任意取值的答案,这里需要从高位到底位依次固定。
对于[0,22345],最高为取0,1时,其余4位是可以随意取得,但是最高为取2时,其他位的取值是受限制的。
而且,最高位取0时需要单独考虑( 思考一下吧:) )。
也就是最终答案被分成了三部分考虑。

  • 最高位为0
  • 最高位为[1,最高位-1]
  • 最高位,其他位受限制

最高位为0时,只需要dp[i-1][1-9][k] ,dp[i-2][1-9][k],… ,dp[1][1-9][k]求和就好了。

最高位为[1,最高位-1]时,只需要dp[i][1–最高位-1][k]求和。

最高位,其他位受限制时,固定最高位,此时K-最高位是其他位的交错和要求。具体的正负号变化需要思考:)

代码:

//#define __LOCAL__DEBUG__

#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <fstream>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <list>
#include <stdexcept>
#include <functional>
#include <utility>
#include <ctime>
using namespace std;

#define PB push_back
#define MP make_pair

#define REP(i,n) for(i=0;i<(n);++i)
#define FOR(i,l,h) for(i=(l);i<=(h);++i)
#define FORD(i,h,l) for(i=(h);i>=(l);--i)

typedef vector<int> VI;
typedef vector<string> VS;
typedef vector<double> VD;
typedef long long LL64;
typedef unsigned long long LL65;
typedef pair<int,int> PII;

LL64 dp[20][20][200];
LL64 dpcnt[20][20][200];
LL64 dp10[20];
const LL64 mod=1e9+7;
char l[100],r[100];
int K;
LL64 solve(char *buf,int K){
    LL64 ANSL=0,ANSR=0,k,ii,jj;
    int kk,i,j;
    int len=strlen(buf);
    dp10[0]=1;
    for(i=1;i<20;i++) dp10[i]=(dp10[i-1]*10)%mod;
    for(i=1;i<len;i++){
        if(i%2==1){
            kk=K;
        }else kk=-K;
        for(j=1;j<10;j++){
            ANSR=(ANSR+dp[i][j][kk+100])%mod;
        }
    }
    k=1;
    ii=0;jj=0;
    for(i=0;i<len;i++){
        if((len-i)%2==1) kk=K;
        else kk=-K;
        //ii=(ii+(dp10[len-i-1]*(buf[i]-'0'))%mod)%mod;
        if(i==0)
            for(j='1';j<buf[i];j++){
                ANSR=(ANSR+dp[len-i][j-'0'][kk+100])%mod;
            }
        else{
            for(j='0';j<buf[i];j++){
                ANSR=(ANSR+dp[len-i][j-'0'][kk+100]+(ii*dpcnt[len-i][j-'0'][kk+100])%mod)%mod;
            }
        }
        K=-(K-(buf[i]-'0'));
        ii=(ii+(dp10[len-i-1]*(buf[i]-'0'))%mod)%mod;
    }
    if(K==0) ANSR=(ANSR+ii)%mod;
    return ANSR;
}
int main(){
#ifndef __LOCAL__DEBUG__
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
#else
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    int i,j,k,n,m,t,T;
    int ii,jj;
    LL64 L,R;
    cin>>L>>R>>K;
    if(L>0) L--;
    stringstream strm;
    strm<<L<<' '<<R<<endl;
    strm>>l>>r;

    memset(dp,0,sizeof(dp));
    memset(dpcnt,0,sizeof(dpcnt));
    for(j=0;j<10;j++){
        dp[1][j][j+100]=j;
        dpcnt[1][j][j+100]=1;
    }
    LL64 kk=1;
    for(i=2;i<20;i++){
        kk=(kk*10)%mod;
        for(j=0;j<10;j++){
            for(k=0;k<200;k++){
                if(i%2==1 && k-j>=0){
                    for(jj=0;jj<10;jj++){
                        dp[i][j][k]+=(dp[i-1][jj][k-j] + (j*((dpcnt[i-1][jj][k-j]*kk)%mod))%mod)%mod;
                        dpcnt[i][j][k]=(dpcnt[i][j][k]+dpcnt[i-1][jj][k-j])%mod;
                    }
                }else if(i%2==0 && k+j<200){
                    for(jj=0;jj<10;jj++){
                        dp[i][j][k]+=(dp[i-1][jj][k+j] + (j*((dpcnt[i-1][jj][k+j]*kk)%mod))%mod)%mod ;
                        dpcnt[i][j][k]=(dpcnt[i][j][k]+dpcnt[i-1][jj][k+j])%mod;
                    }
                }
            }
        }
    }
    LL64 ANSL=0,ANSR=0;

    ANSL=solve(l,K);
    ANSR=solve(r,K);
    //cout<<ANSL <<"  ----   "<<ANSR<<endl;
    cout<<(ANSR-ANSL+mod)%mod<<endl;
    return 0;
}


扫买关注作者,定期分享技术、算法类文章
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值