码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ2757: [SCOI2012]Blinker的仰慕者

时间:2017-02-14 20:31:32      阅读:499      评论:0      收藏:0      [点我收藏+]

标签:space   turn   i+1   lower   size   type   print   include   数位dp   

这题……我一般数位dp都是直接用一个dp把所有东西算完,然而……多组询问每次重新dp会T……然后只好先预处理再查询,然后还搞不了k=0,只好再单独写一个dp……烦死了……

k!=0时,数位的乘积总共就几万种,离散化再预处理转移。f[i][j]表示前i位,乘积为j。k==0时,f[i][2][2][2][2]表示第i位,是否卡下界,是否卡上界,乘积是否为0,是否全是前导0。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int p=20120427;
const int M=20;
const int N=6e4;
int n,q,z1[N][10],z2[N][10];
ll x,y,k,e[M]={1},z3[N],f[M][N][2];
int sol(int r1,ll r2){
	int m=0,r3[M],r4=0;
	for(ll i=r2;i;i/=10)
		r3[m++]=i%10;
	for(int i=1;i<m;++i)
		r4=(r4+f[i][r1][1])%p;
	for(int i=m-1;~i;--i){
		ll r5=r2/e[i+1]*10;
		for(int j=1;j<r3[i];++j)
			if(~z2[r1][j]){
				ll*r6=f[i][z2[r1][j]];
				r4=(r4+r6[1]+(r5+j)*e[i]%p*r6[0])%p;
			}
		r1=z2[r1][r3[i]];
		if(!~r1)break;
	}
	return r4;
}
int cal(ll i){
	return lower_bound(z3,z3+n,i)-z3;
}
namespace ns1{
	int m,z1[M],z2[M],f[M][2][2][2][2][2];
	void sol(){
		for(--x,++y,m=0;y;++m){
			z1[m]=x%10,x/=10;
			z2[m]=y%10,y/=10;
		}
		for(int i=m;i<M;++i)
			z1[i]=z2[i]=0;
		memset(f,0,sizeof f);
		f[m][1][1][0][1][0]=1;
		for(int a=m-1;~a;--a)
			for(int b=1;~b;--b)
				for(int c=1;~c;--c){
					int u=b?z1[a]:0,v=c?z2[a]:9;
					for(int d=1;~d;--d){
						int(*s)[2]=f[a+1][b][c][d];
						for(int e=u;e<=v;++e){
							int(*t)[2][2]=f[a][b&e==z1[a]][c&e==z2[a]];
							(t[d|!e][0][0]+=s[0][0])%=p;
							(t[d|!e][0][1]+=s[0][1]*10+e*s[0][0])%=p;
							(t[0][!e][0]+=s[1][0])%=p;
							(t[0][!e][1]+=e*s[1][0])%=p;
						}
					}
				}
		printf("%d\n",f[0][0][0][1][0][1]);
	}
}
int main(){
	for(int i=1;i<M;++i)
		e[i]=e[i-1]*10;
	const ll v=16e16;
	for(ll a=1;a<v;a*=2)
		for(ll b=a;b<v;b*=3)
			for(ll c=b;c<v;c*=5)
				for(ll d=c;d<v;d*=7)z3[n++]=d;
	sort(z3,z3+n);
	memset(z1,-1,sizeof z1);
	memset(z2,-1,sizeof z2);
	for(int j=0;j<n;++j)
		for(int i=9;i;--i)
			if(z3[j]*i<v)
				z2[z1[j][i]=cal(z3[j]*i)][i]=j;
	f[0][0][0]=1;
	for(int i=0;i<18;++i)
		for(int j=0;j<n;++j){
			ll*s=f[i][j];
			if(!s[0])continue;
			s[0]%=p;
			for(int k=9;k;--k)
				if(~z1[j][k]){
					ll*t=f[i+1][z1[j][k]];
					t[0]+=s[0];
					(t[1]+=s[1]+k*e[i]%p*s[0])%=p;
				}
		}
	scanf("%d",&q);
	while(q--){
		scanf("%lld%lld%lld",&x,&y,&k);
		if(!k)ns1::sol();
		else if(k>=v)puts("0");
		else{
			int j=cal(k);
			if(z3[j]!=k)puts("0");
			else
				printf("%d\n",(sol(j,y+1)-sol(j,x)+p)%p);
		}
	}
}

  

BZOJ2757: [SCOI2012]Blinker的仰慕者

标签:space   turn   i+1   lower   size   type   print   include   数位dp   

原文地址:http://www.cnblogs.com/f321dd/p/6399013.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!