{数位DP+longlong边界溢出} 交错和问题

妈蛋真是脑洞大开!

看看这个交错和问题:

各种溢出和逻辑上错误导致的越界、对象错误防不胜防。

描述

给定一个数 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

状态:

[i][j][k]

边界:

  • i=[0,len(x)) ,len即x的十进制位数。
  • k属于[0,n),其中0对应minN,n-1对应maxN. 所以n=maxN-minN+1.
递推方程:

  • E{cnt[i][j][k]} = _cnt[i][k] => cnt[i+1][j][k+(-1)^(i+1)*j]
  • E{num[i][j][k]} = _num[i][k], _num[i][k]+_cnt[i][k] * 10^(i+1) => num[i+1][j][k+(-1)^(i+1)*j]


#include <iostream>
#include <vector>
#include <assert.h>
#include <math.h>
using namespace std;

typedef long long int ll;
typedef pair<ll,ll> Pair;//@pair<int,ll> can overflow!!! should be pair<ll,ll>
#define MOD 1000000007
int dump(ll x,int a[]){
	int i=0;while(x>0){ a[i++]=x%10;x/=10; }
	if(i==0) a[0]=0,i=1;
	return i;
}
ll dp(ll x, int K){
	// return the count of number in [0~x) that f(number)=K
	if(x==0) return 0;
	int a[18];int len=dump(x,a);

	int minN=0-(len/2)*9,maxN=(len+1)/2*9;//0909.. 9090..
	if(K<minN||K>maxN) return 0;
	int delta=0-minN,n=maxN-minN+1;

	p[i][j][k] : delta+ (+/-)xi .... -x1 + x0 = k, xi = j
	vector<vector<vector<Pair> > > p(len,vector<vector<Pair> >(10,
				vector<Pair>(n,Pair(0,0))));

	//init
	for(int j=0;j<10;j++) p[0][j][j+delta]=Pair(1,j); i=0. j=x0, x0+delta=k
	for(int i=0;i<len-1;i++){
		vector<Pair> cnt(n,Pair(0,0));
		for(int j=0;j<10;j++){
			for(int k=0;k<n;k++){
				Pair &s=p[i][j][k];
				cnt[k].first=(s.first+cnt[k].first)%MOD;
				cnt[k].second=(s.second+cnt[k].second)%MOD;
			}
		}
		// [i][k] => [i+1][j][k+(+/-)j]
		for(int j=0;j<10;j++){
			int fh=pow(-1,i+1);
			ll d=(ll)pow(10,i+1)%MOD*j%MOD;//@error:pow(10,i+1)*j can overflow
			for(int k=0;k<n;k++){
				if(k+fh*j<0||k+fh*j>=n) continue;//@attention: here k+fh*j can be unavailable
				Pair &s=p[i+1][j][k+fh*j];
				s.first=cnt[k].first;
				assert(d<MOD);
				assert(s.first<MOD);
				s.second=(d*s.first%MOD+cnt[k].second)%MOD;
			}
		}
	}

	// count of number in [0~xm..x3x2x1x0] , where m<len-1
	ll num=0;
	//int b[len];
	for(int i=len-2;i>=0;i--){
		//b[i+1]=0;
		int j;
		int fh=pow(-1,i); 
		if(i==0) j=0;
		else j=1;
		 if(fh==1)  (k-delta)=K; else  -(k-delta)=K
		int k=fh*K+delta;
		if(!(k>=0&&k<n)) continue;//here k can be unavailable
		// assert(k>=0&&k<n);//@error: logic error, here k can be out of [0,n)
		for(;j<10;j++){
			//b[i]=j;
			num=(num+p[i][j][k].second)%MOD;
		}
	}

	//count of number in [10000...00,x)
	ll s=0;
	int lst=0;
	int fh=pow(-1,len-1);
	for(int i=len-1;i>=0;i--){
		int j; 
		if(i==len-1) j=1;
		else j=0;
		int k=(K-lst)*fh+delta;
		// assert(k>=0&&k<n);//@error: logic error, here k can be out of [0,n)
		if(!(k>=0&&k<n)) ;//@attention: k can be unavailable
		else
		for(;j<a[i];j++){
			 lst+fh*(k-delta)=K, k=(K-lst)/fh+delta
			Pair &q=p[i][j][k];
			ll d=(q.second+s*q.first%MOD)%MOD;
			num=(num+d)%MOD;
		}

		lst+=pow(-1,i)*fh*a[i];
		// s+=pow(10,i)*a[i]; //@error: here s will overflow!!!!
		s=(s+(ll)pow(10,i)*a[i]%MOD)%MOD;
                                                 //@attention: (ll) has higher priority than *
		                                 //@attention: pow(10,i)*a[i] will not overflow
	}
	return num;
}
int main(){
	ll l,r;int k;
	debug
	// for(r=999999;r<999999999;r+=10000){
		// for(k=1;k<100;k++){
			// cout<<dp(r,k)<<endl;
		// }
	// }
	cin>>l>>r>>k;
	ll x1=dp(l,k);
	ll x2=dp(r,k);
	ll cnt=(x2-x1)%MOD;
	int b[18];int len=dump(r,b);
	int fh=pow(-1,len-1);int kk=0;
	for(int i=len-1;i>=0;i--) kk+=fh*pow(-1,i)*b[i];
	// if(kk==k) cnt++;//@error: logic error: cnt++ should be cnt+=r
	if(kk==k) cnt=(cnt+r%MOD)%MOD;
	cout<<(cnt+MOD)%MOD<<endl;
	return 0;
}


或者:

#include <cstdio>
#include <iostream>
using namespace std;
typedef long long LL;
const LL Mod=1000000007;
int k0;
LL cnt[20][20*9], sum[20][20*9];

void dp(int n)
{
	int sign=-1;
	cnt[0][k0]=1; sum[0][k0]=0;
	for (int i=0; i<n; ++i)
	{
		sign=-sign;
		for (int j=-i/2*9; j<=(i+1)/2*9; ++j)
			for (int l=0; l<=9; ++l)
			{
				int x=j+sign*l+k0;
				cnt[i+1][x]=(cnt[i+1][x]+cnt[i][j+k0])%Mod;
				sum[i+1][x]=(sum[i+1][x]+sum[i][j+k0]*10+cnt[i][j+k0]*l)%Mod;
			}
	}
}

LL calc(int n, int k)
{
	if (n<=0) return 0;
	LL res=calc(n-1, k);
	LL base=1;
	for (int i=1; i<n; ++i) base*=10;
	for (int i=1; i<=9; ++i) res=(res+i*base%Mod*cnt[n-1][i-k+k0]+sum[n-1][i-k+k0])%Mod;
	return res;
}

LL work(LL num, int k)
{
	int n=0, a[20];
	LL base=1;
	for (LL x=num; x; x/=10) a[n++]=x%10, base*=10;
	int sign=-1, k1=k;
	LL res=calc(n-1, k), pre=0;
	for (int i=n-1; i>=0; --i)
	{
		base/=10;
		sign=-sign;
		pre*=10;
		for (int j=(i==n-1? 1:0); j<a[i]; ++j)
		{
			int suc=(k1-j*sign)*(-sign)+k0;
			res=(res+(pre+j)*base%Mod*cnt[i][suc]+sum[i][suc])%Mod;
		}
		pre+=a[i];
		k1-=a[i]*sign;
	}
	if (k1==0) res=(res+pre)%Mod;
	return res;
}

int main()
{
	LL l, r;
	int k;
	cin>>l>>r>>k;
	int n=0;
	for (LL x=r; x; x/=10) ++n;
	k0=n/2*9;
	dp(n);
	cout<<((work(r, k)-work(l-1, k))%Mod+Mod)%Mod<<endl;
	return 0;
}


另一种写法

//#pragma comment(linker,"/STACK:102400000,102400000")
template<class T> inline T sqr(T x) { return x * x; }
typedef long long LL;
typedef unsigned long long ULL;
typedef long double LD;
typedef pair<int, int> PII;
typedef pair<PII, int> PIII;
typedef pair<LL, LL> PLL;
typedef pair<LL, int> PLI;
typedef pair<LD, LD> PDD;
#define MP make_pair
#define PB push_back
#define sz(x) ((int)(x).size())
#define clr(ar,val) memset(ar, val, sizeof(ar))
#define istr stringstream
#define FOR(i,n) for(int i=0;i<(n);++i)
#define forIt(mp,it) for(__typeof(mp.begin()) it = mp.begin();it!=mp.end();it++)
const double PI = acos(-1.0);

#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define lowbit(u) (u&(-u))

using namespace std;

#define MOD 1000000007

PLL dp[25][205][2][2];
int digit[25];
LL l,r,k,p10[25];

PLL dfs(int cur,int sum,int x,int lead,int limit){
	if(cur<0){
		if(sum==k) return MP(0,1);
		return MP(0,0);
	}
	if(!limit&&~dp[cur][sum][x][lead].first) return dp[cur][sum][x][lead];
	if(!lead) x = 1;
	LL ans = 0,cnt = 0;
	int ed = limit?digit[cur]:9;
	int p = 1;
	if(x==0) p = -1;
	for(int i = 0;i<=ed;i++){
		PLL ret = dfs(cur-1,sum+i*p,!x,lead||i,limit&&i==ed);
		ans+=i*p10[cur]%MOD*ret.second%MOD+ret.first;
		ans%=MOD;
		cnt+=ret.second;
		cnt%=MOD;
	}
	if(!limit) dp[cur][sum][x][lead] = MP(ans,cnt);
	return MP(ans,cnt);
}

PLL solve(LL n){
	if(n<0) return MP(0,0);
	int cnt = 0;
	while(n){
		digit[cnt++] = n%10;
		n/=10;
	}
	return dfs(cnt-1,100,1,0,1);
}

int main(void){
#ifndef ONLINE_JUDGE
	//freopen("/Users/mac/Desktop/data.in","r",stdin);
#endif
	p10[0] = 1;
	for(int i = 1;i<=20;i++) p10[i] = 1ll*p10[i-1]*10%MOD;
	memset(dp,-1,sizeof(dp));
	scanf("%lld %lld %lld",&l,&r,&k);
	k+=100;
	LL ret = solve(r).first-solve(l-1).first;
	if(ret<0) ret+=MOD;
	printf("%lld\n",ret);
	return 0;
}

或者

#pragma  comment(linker, "/STACK:36777216")
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define  lc(x) (x << 1)
#define  rc(x) (lc(x) + 1)
#define  lowbit(x) (x & (-x))
#define  PI    (acos(-1))
#define  lowbit(x) (x & (-x))
#define  EPS   1e-10
#define  MAXN  100005
#define  MAXM  2005
#define  LL    long long
#define  DB    double
#define  ULL   unsigned long long
#define  PII   pair<int, int>
#define  INF   0x3fffffff
#define  PB    push_back
#define  MP    make_pair
#define  MOD   1000000007

using namespace std;

LL f[20][405][2][2], f2[20][405][2][2], ten[20], dig[20];

LL Mul(LL a, LL b){
    a %= MOD, b %= MOD;
    return (a * b) % MOD;
}

int K;

LL dp(int pos, int sum, bool first, bool ud, bool flag){
    if(sum < 0 || sum > 400) return 0;
    if(pos == -1) return (sum == (200 + K));
    if(!flag && f[pos][sum][first][ud] != -1)
        return f[pos][sum][first][ud];
    LL res = 0;
    for(int i = 0, l = flag ? dig[pos] : 9; i <= l; i ++){
        if(first == true){
            if(i == 0) res += dp(pos - 1, sum, 1, 0, flag && i == l);
            else res += dp(pos - 1, sum + i, 0, 1, flag && i == l);
        }
        else{
            int tmp;
            if(ud == 0) tmp = sum + i; else tmp = sum - i;
            res += dp(pos - 1, tmp, 0, !ud, flag && i == l);
        }
        res %= MOD;
    }
    return flag ? res : f[pos][sum][first][ud] = res;
}

LL dp2(int pos, int sum, bool first, bool ud, bool flag){
    if(sum < 0 || sum > 400) return 0;
    if(pos == -1) return 0;
    if(!flag && f2[pos][sum][first][ud] != -1)
        return f2[pos][sum][first][ud];
    LL res = 0;
    for(int i = 0, l = flag ? dig[pos] : 9; i <= l; i ++){
        LL has = 0;
        if(first == true){
            if(i == 0) has = dp(pos - 1, sum, 1, 0, flag && i == l), res += dp2(pos - 1, sum, 1, 0, flag && i == l);
            else has = dp(pos - 1, sum + i, 0, 1, flag && i == l), res += dp2(pos - 1, sum + i, 0, 1, flag && i == l);
        }
        else{
            int tmp;
            if(ud == 0) tmp = sum + i; else tmp = sum - i;
            has = dp(pos - 1, tmp, 0, !ud, flag && i == l);
            res += dp2(pos - 1, tmp, 0, !ud, flag && i == l);
        }
        res %= MOD;
        LL tmp;
        tmp = (LL) i * ten[pos] % MOD;

        tmp = (tmp * has) % MOD;
        res = (res + tmp) % MOD;

        //res += Mul(Mul((LL) i, ten[pos]), has);
        res %= MOD;
    }
    return flag ? res : f2[pos][sum][first][ud] = res;
}

LL calc(LL x){
    if(x < 0) return 0;
    int cnt = 0;
    while(x)
        dig[cnt ++] = x % 10, x /= 10;
    return dp2(cnt - 1, 200, 1, 0, 1) % MOD;
}

int t; LL l, r;

int main(){
    //freopen("in.txt", "r", stdin);
    ten[0] = 1;
    for(int i = 1; i < 20; i ++)
        ten[i] = (ten[i - 1] * 10) % MOD;
    while(cin >> l >> r >> K){
        memset(f, -1, sizeof(f)); memset(f2, -1, sizeof(f2));
        LL k2 = calc(r), k1 = calc(l - 1);
        LL ans = (k2 - k1 + MOD) % MOD;
        cout << ans << endl;
        //printf("%lld\n", ans);
    }
}

或者:

/*
 * temp.cpp
 *
 *  Created on: 2012-7-18
 *      Author: BSBandme
 */
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <fstream>
#include <string.h>
#include <cstdio>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <cassert>
#include <list>
#include <iomanip>
#include <math.h>
#include <deque>
#include <utility>
#include <map>
#include <set>
#include <bitset>
#include <numeric>
#include <climits>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <functional>
#include <sstream>
#include <tr1/unordered_set>
#include <tr1/unordered_map>

using namespace std;
using namespace tr1;

#define mpr make_pair
typedef unsigned int ui;
typedef unsigned long long ull;
typedef long long ll;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <double, double> pdd;
typedef vector <int> vi;
typedef vector <ll> vll;
typedef vector <double> vd;
typedef vector <string> vs;
typedef map <string, int> mpsi;
typedef map <double, int> mpdi;
typedef map <int, int> mpii;

const double pi = acos(0.0) * 2.0;
const double eps = 1e-12;
const int step[8][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}};

template <class T> inline T abs1(T a) {return a < 0 ? -a : a;}

template <class T> inline T max1(T a, T b) { return a > b ? a : b; }
template <class T> inline T max1(T a, T b, T c) { return max1(max1(a, b), c); }
template <class T> inline T max1(T a, T b, T c, T d) { return max1(max1(a, b, c), d); }
template <class T> inline T max1(T a, T b, T c, T d, T e) { return max1(max1(a, b, c, d), e); }
template <class T> inline T min1(T a, T b) { return a < b ? a : b; }
template <class T> inline T min1(T a, T b, T c) { return min1(min1(a, b), c); }
template <class T> inline T min1(T a, T b, T c, T d) { return min1(min1(a, b, c), d); }
template <class T> inline T min1(T a, T b, T c, T d, T e) { return min1(min1(a, b, c, d), e); }

inline int jud(double a, double b){
	if(abs(a) < eps && abs(b) < eps) return 0;
	else if(abs1(a - b) / abs1(a) < eps) return 0;
	if(a < b) return -1;
	return 1;
}
template <typename t> inline int jud(t a, t b){
	if(a < b) return -1;
	if(a == b) return 0;
	return 1;
}

// f_lb == 1代表返回相同的一串的左边界,f_small == 1代表返回如果没有寻找的值返回小的数
template <typename it, typename t1>
inline int find(t1 val, it a, int na, bool f_small = 1, bool f_lb = 1){
	int be = 0, en = na - 1;
	if(*a <= *(a + na - 1)){
		if(f_lb == 0) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != 1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != -1) en = mid;
			else be = mid + 1;
		}
		if(f_small && jud(*(a + be), val) == 1) be--;
		if(!f_small && jud(*(a + be), val) == -1) be++;
	} else {
		if(f_lb) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != -1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != 1) en = mid;
			else be = mid + 1;
		}
		if(!f_small && jud(*(a + be), val) == -1) be--;
		if(f_small && jud(*(a + be), val) == 1) be++;
	}
	return be;
}

template <class T> inline T lowb(T num) {return num & (-num); }
inline int bitnum(ui nValue) { return __builtin_popcount(nValue); }
inline int bitnum(int nValue) { return __builtin_popcount(nValue); }
inline int bitnum(ull nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitnum(ll nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitmaxl(ui a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(int a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(ull a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
inline int bitmaxl(ll a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }

long long pow(long long n, long long m, long long mod = 0){
	if(m < 0) return 0;
	long long ans = 1;
	long long k = n;
	while(m){
		if(m & 1) {
			ans *= k;
			if(mod) ans %= mod;
		}
		k *= k;
		if(mod) k %= mod;
		m >>= 1;
	}
	return ans;
}

#define  MOD 1000000007
template <class t1, class t2>
inline void add(t1 &a, t2 b, int mod = -1) {
	if(mod == -1) mod = MOD;
	a += b;
	while(a >= mod) a -= mod;
	while(a < 0) a += mod;
}


//#define debug
//.........................mi.......feng......xian.......xia.......jin.......zhi.......hack...............................................


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值