BZOJ 1183 Croatian 2008 Umnozak【デジタルDP】*
BZOJ1183 Croatian2008 Umnozak
Description
1つの数を定義するdigit-productは、その各ビット上の数値の積であり、1つの数を定義するself-productは、それ自体にそれを乗じたdigit-pr oductである.プログラミングはself-productのaとbの間の数の個数を求めます.
Input
2つの整数a,b(1≦a≦b<10^18).
Output
1つの整数、self-productのaとbの間の数の個数.
Sample Input
145 192
Sample Output
4
デジタルDP、私はdigit-productが含む質因子が最大で2,3,5,7しかないことを発見しました.digit-productは原数より厳格に小さいので、digit-productは1 e 9を超えません.だから、私たちはこの数を列挙することができます.わずかな可能性しかありません.
そしてdigit-productを決定してから原数の上下境界を決定し,digit-productでは2,3,5,7の質量因子個数を用いてDPを行い,境界問題に注意する
...
どうせ私はスケジュール通りに調整した.
スレッド:
Description
1つの数を定義するdigit-productは、その各ビット上の数値の積であり、1つの数を定義するself-productは、それ自体にそれを乗じたdigit-pr oductである.プログラミングはself-productのaとbの間の数の個数を求めます.
Input
2つの整数a,b(1≦a≦b<10^18).
Output
1つの整数、self-productのaとbの間の数の個数.
Sample Input
145 192
Sample Output
4
デジタルDP、私はdigit-productが含む質因子が最大で2,3,5,7しかないことを発見しました.digit-productは原数より厳格に小さいので、digit-productは1 e 9を超えません.だから、私たちはこの数を列挙することができます.わずかな可能性しかありません.
そしてdigit-productを決定してから原数の上下境界を決定し,digit-productでは2,3,5,7の質量因子個数を用いてDPを行い,境界問題に注意する
...
どうせ私はスケジュール通りに調整した.
#include
using namespace std;
typedef long long LL;
LL l,r,ans=0;
LL dp[18][30][19][13][11];
LL f[4]={2,3,5,7};
LL k[4]={0,0,0,0};
LL cnt[10][4]={
{0,0,0,0},
{0,0,0,0},
{1,0,0,0},
{0,1,0,0},
{2,0,0,0},
{0,0,1,0},
{1,1,0,0},
{0,0,0,1},
{3,0,0,0},
{0,2,0,0}
};
LL dfs(LL len,LL a,LL pot,LL l_line,LL r_line){
LL b=a+pot-1;
if(a>r_line||breturn 0;
if(len==18)return (!k[0])&&(!k[1])&&(!k[2])&&(!k[3]);
bool mem=(a>=l_line&&b<=r_line);
if(mem&&dp[len][k[0]][k[1]][k[2]][k[3]]>=0)
return dp[len][k[0]][k[1]][k[2]][k[3]];
pot/=10;
LL res=0;
for(LL i=(a!=0);i<=9;++i){
LL t=1;
for(LL j=0;j<4;j++)if(cnt[i][j]>k[j])t=0;
if(!t)continue;
for(LL j=0;j<4;j++)k[j]-=cnt[i][j];
res+=dfs(len+1,a+i*pot,pot,l_line,r_line);
for(LL j=0;j<4;j++)k[j]+=cnt[i][j];
}
if(mem)dp[len][k[0]][k[1]][k[2]][k[3]]=res;
return res;
}
LL getL(LL a,LL b){return (a+b-1)/b;}
LL getR(LL a,LL b){return a/b;}
void getans(LL up,LL prod,LL tip){
if(prod>(LL)1e9||prod*prod>up)return;
if(tip==4){
ans+=dfs(0,0,(LL)1e18,getL(l,prod),getR(r,prod));
return;
}
getans(up,prod,tip+1);
++k[tip];
getans(up,prod*f[tip],tip);
--k[tip];
}
int main(){
cin>>l>>r;
memset(dp,-1,sizeof(dp));
getans(r,1,0);
printf("%lld
",ans);
return 0;
}
スレッド:
#include
#include
#include
#include
using namespace std;
typedef long long llint;
llint memo[18][30][19][13][11];
int f[4] = { 2, 3, 5, 7 };
int k[4] = { 0, 0, 0, 0 };
int code[10][4] = {
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 1, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 2, 0, 0, 0 },
{ 0, 0, 1, 0 },
{ 1, 1, 0, 0 },
{ 0, 0, 0, 1 },
{ 3, 0, 0, 0 },
{ 0, 2, 0, 0 }
};
llint rec( int digits, llint a, llint pot, llint lo, llint hi ) {
llint b = a + pot-1;
if( a > hi || b < lo ) return 0;
if( digits == 18 ) return !k[0] && !k[1] && !k[2] && !k[3];
int memoize = 0;
if( a >= lo && b <= hi ) memoize = 1;
if( memoize && memo[digits][k[0]][k[1]][k[2]][k[3]] >= 0 )
return memo[digits][k[0]][k[1]][k[2]][k[3]];
pot /= 10;
llint ret = 0;
for( int digit = (a!=0); digit <= 9; ++digit ) {
int ok = 1;
for( int i = 0; i < 4; ++i ) ok &= code[digit][i] <= k[i];
if( !ok ) continue;
for( int i = 0; i < 4; ++i ) k[i] -= code[digit][i];
ret += rec( digits+1, a + digit*pot, pot, lo, hi );
for( int i = 0; i < 4; ++i ) k[i] += code[digit][i];
}
if( memoize ) memo[digits][k[0]][k[1]][k[2]][k[3]] = ret;
return ret;
}
llint lo, hi;
llint rjesenje;
llint ceil( llint a, llint b ) { return (a+b-1)/b; }
llint floor( llint a, llint b ) { return a/b; }
void gen( llint limit, llint product, int factor ) {
if( product > 1000000000 || product*product > limit ) return;
if( factor == 4 ) {
rjesenje += rec( 0, 0, 1000000000000000000LL, ceil(lo,product), floor(hi,product) );
return;
}
gen( limit, product, factor + 1 );
++k[factor];
gen( limit, product*f[factor], factor );
--k[factor];
}
int main( void ) {
scanf( "%lld%lld", &lo, &hi );
memset( memo, -1, sizeof memo );
gen( hi, 1, 0 );
printf( "%lld
", rjesenje );
return 0;
}