原题链接:http://codeforces.com/contest/855/problem/E
题目大意:一个数字在B进制下为魔法数字当且仅当其在B进制下,0到B-1在其数位上均出现偶数次。问从L到R的B进制下魔法数字的数量。(L<R<10^18 , 2<=B<=10)
首先数位DP的框架大多是不会变的,重点在于如何求已知前a个数位上的数字,可以使得其为魔法数字的后面b个未知的数位上的数字排布方案数。
假设前面a个数位中有sum个数字出现了奇数次,于是对于这sum个数字就需要在后面各出现奇数次,如果没有填充完后面的所有数位,则需要继续填充除了sum个数字外的数字,同时再次填充的数字必须各自出现偶数次才能使其为魔法数字。
因为数位的数量比较少,可以直接暴力枚举出现的次数。
最后由于多组询问,加上记忆化以后就可以AC了。
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline void read(int &x){
char ch;
bool flag=false;
for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true;
for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
x=flag?-x:x;
}
inline void read(long long &x){
char ch;
bool flag=false;
for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true;
for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
x=flag?-x:x;
}
inline void write(int x){
static const int maxlen=100;
static char s[maxlen];
if (x<0) { putchar('-'); x=-x;}
if(!x){ putchar('0'); return; }
int len=0; for(;x;x/=10) s[len++]=x % 10+'0';
for(int i=len-1;i>=0;--i) putchar(s[i]);
}
inline void write(long long x){
static const int maxlen=100;
static char s[maxlen];
if (x<0) { putchar('-'); x=-x;}
if(!x){ putchar('0'); return; }
int len=0; for(;x;x/=10) s[len++]=x % 10+'0';
for(int i=len-1;i>=0;--i) putchar(s[i]);
}
long long b,l,r;
long long P[20];
long long f[ 300][ 20][20][20];
long long C[ 300][300];
map< pair<int, long long> , long long > M;
long long get_C(int n ,int m){
if ( C[ n][m]!=-1)
return C[n][m];
long long ans=1;
for (int i=1;i<=m;i++)
ans=ans*(n-i+1)/i;
C[n][m]=ans;
return ans;
}
long long get_num(int wei,int tot,int tmp,int cnt){
if ( wei < tot )
return 0;
if ( cnt > tmp )
return 0;
if ( ( wei==0 )&& ( tot==0) )
return get_C( tmp , cnt );
if ( f[ wei ][ tot ][ tmp ][ cnt ]!=-1)
return f[ wei ][ tot ][ tmp ][ cnt ];
long long ans=0;
if (tot>0)
{
for (int i=1;i<=wei-tot+1;i+=2)
ans+=get_C( wei , i )*get_num( wei-i , tot-1 , tmp,cnt);
}
else
{
for (int i=2;i<=wei;i+=2)
ans+=get_C( wei , i )*get_num( wei-i , tot , tmp , cnt+1);
}
f[ wei ][ tot ][ tmp ][ cnt ]=ans;
return ans;
}
long long get_ans(int b,long long x){
if ( M.count( make_pair( b , x ) ) )
return M[ make_pair( b , x ) ];
if (x==0)
return 1;
unsigned long long tmp=1;
long long wei=1;
while ( tmp*b<= x)
{
tmp=tmp*b;
wei++;
}
if ( wei%2==1 )
return get_ans( b , tmp-1 );
long long ans=get_ans(b,tmp-1);
long long now=0;
long long sum=0;
bool op=1;
long long TMPX=x;
while ( wei )
{
if ( sum>wei)
break;
for (int i=op;i<x/tmp;i++)
{
if ( ( ( 1<<i )&now )==0)
sum++;
else
sum--;
ans+=get_num( wei-1 , sum ,b-sum,0);
if ( ( ( 1<<i ) &now )==0)
sum--;
else
sum++;
}
if ( ( now & ( ( 1<< (x/tmp) ) ) )==0 )
sum++;
else
sum--;
now=now^( ( 1<< (x/tmp) ) );
x=x%tmp;
tmp=tmp/b;
op=0;
wei--;
}
if ( sum==0 )
ans++;
M[ make_pair(b,TMPX) ]=ans;
return ans;
}
void doit(){
read(b); read(l);read(r);
long long tmp=get_ans(b,r)-get_ans(b,l-1);
write(tmp);
puts("");
}
int main(){
//freopen("a.out","w",stdout);
memset(f,-1,sizeof(f));
memset(C,-1,sizeof(C));
int T;
read(T);
for (int I=1;I<=T;I++)
doit();
return 0;
}