题目描述
Description
Lambda受任于某情报站,他的工作是获取敌人情报。一次他在破解密码系统时,得到了一个N位B进制数φ,满足φ≡V (mod M)。他发现组成φ的数字很奇特。为了验证φ的特殊性,他将所有模M为V的N位B进制数,按照各数位构成的集合分类,并想知道每一类数各有多少个。
Input
输入共一行,包含四个整数N, B, M, V。
Output
输出共2B-1行,每行包含一个集合S和整数Ans[S],以单个空格隔开。集合S用其所有元素的递减序列表示,如{2, 0, 1}表示为“210”。Ans[S]表示数位集合为S的满足以上性质的数的数目。
集合按照字典序输出,每个集合只输出一次。由于Ans[S]可能很大,只需输出它除以10007的余数即可。
Sample Input
3 3 4 1
Sample Output
0 0
1 1
10 1
2 0
20 0
21 2
210 1
Data Constraint
Hint
【样例说明】
在所有三位三进制数((100)3~(222)3)中,模4为1的数为(100)3, (111)3, (122)3, (210)3, (221)3。数位集合为{1}的有1个(111)3,数位集合为{1, 0}的有1个(100)3,数位集合为{2, 1}的有2个((122)3, (221)3),数位集合为{2, 1, 0}的有1个(210)3。
70%
显然可以想到矩乘优化dp+容斥算答案
枚举数字集,设f[i]表示当前模m为i的方案数
考虑转移
每次加上一位,f[i]–>f[(i*B+s)%m](s∈可用数字)
然后可以考虑所有s,在合法转移处[(i*B+s)%m][i]+1转移方案数
特判第一位,矩乘n-1遍
时间复杂度:O(2BM3log n+3B)
code
#include <iostream>
#include <cstdlib>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ansmod 10007
using namespace std;
long long ans[1024];
bool bz[10];
int d[10];
int n,len,mod,v,i,j,k,l;
struct matrix{
int f[120][120];
void clear()
{
int i,j;
fo(i,0,mod-1)
{
fo(j,0,mod-1)
f[i][j]=0;
}
}
void chen(matrix b)
{
int i,j,k;
matrix c;
c.clear();
fo(i,0,mod-1)
{
fo(j,0,mod-1)
{
fo(k,0,mod-1)
c.f[i][j]=(c.f[i][j]+f[k][j]*b.f[i][k])%ansmod;
}
}
fo(i,0,mod-1)
{
fo(j,0,mod-1)
f[i][j]=c.f[i][j];
}
}
} a,A;
void qpower(int b)
{
int i;
A=a;
a.clear();
fo(i,0,mod-1)
a.f[i][i]=1;
while (b)
{
if (b&1)
a.chen(A);
A.chen(A);
b>>=1;
}
}
void dfs(int t,int s)
{
int i,j;
if (t>len)
{
if (s)
{
a.clear();
fo(i,0,len-1)
if (bz[i])
{
fo(j,0,mod-1)
++a.f[(j*len+i)%mod][j];
}
qpower(n-1);
fo(i,1,len-1)
if (bz[i])
ans[s]=(ans[s]+a.f[v][i%mod])%ansmod;
}
return;
}
bz[len-t]=0;
dfs(t+1,s<<1);
bz[len-t]=1;
dfs(t+1,(s<<1)+1);
}
void Dfs(int t)
{
int i,j,s1=0,s2=0,bz=1;
if (t>=len)
{
fd(i,len-1,0)
{
switch (d[i])
{
case 0:{
s1=(s1<<1);
s2=(s2<<1);
break;
}
case 1:{
s1=(s1<<1)+1;
s2=(s2<<1);
bz=-bz;
break;
}
case 2:{
s1=(s1<<1)+1;
s2=(s2<<1)+1;
break;
}
}
}
if (s1>s2)
ans[s1]=(ans[s1]+ans[s2]*bz)%ansmod;
return;
}
fd(i,2,0)
{
d[t]=i;
Dfs(t+1);
}
}
void DFS(int t,int s)
{
int i;
if (t>len)
{
if (s)
{
fd(i,len-1,0)
if (bz[i])
printf("%d",i);
printf(" ");
printf("%d\n",(ans[s]+ansmod)%ansmod);
}
return;
}
bz[len-t]=0;
DFS(t+1,s<<1);
bz[len-t]=1;
DFS(t+1,(s<<1)+1);
}
int main()
{
// freopen("a.in","r",stdin);
// freopen("b.out","w",stdout);
// freopen("S8_2_2.in","r",stdin);
scanf("%d%d%d%d",&n,&len,&mod,&v);
dfs(1,0);
Dfs(0);
DFS(1,0);
}
100%
显然M3会超时
因为本题很特殊,可以把两端数接上
所以直接M2转移+维护2k层+快速幂
code
#include <iostream>
#include <cstdlib>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ansmod 10007
using namespace std;
long long ans[1024];
bool bz[10];
int d[10];
int n,len,mod,v,i,j,k,l,Len;
long long Qpower(long long a,int b)
{
long long ans=1;
while (b)
{
if (b&1)
ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
struct type{
int f[120];
int len;
void clear()
{
int i,j;
fo(i,0,mod-1)
f[i]=0;
len=1;
}
void chen(type b)
{
int i,j,k,s=Qpower(Len,b.len);
type c;
c.clear();
fo(i,0,mod-1)
{
fo(j,0,mod-1)
c.f[(i*s+j)%mod]=(c.f[(i*s+j)%mod]+f[i]*b.f[j])%ansmod;
}
fo(i,0,mod-1)
f[i]=c.f[i];
len+=b.len;
}
} a,A;
void qpower(int b)
{
while (b)
{
if (b&1)
a.chen(A);
A.chen(A);
b>>=1;
}
}
void dfs(int t,int s)
{
int i,j;
if (t>len)
{
if (s)
{
a.clear();
fo(i,1,len-1)
if (bz[i])
++a.f[i%mod];
A.clear();
fo(i,0,len-1)
if (bz[i])
++A.f[i%mod];
// if (s==2)
// {
// fo(i,0,mod-1) cout<<a.f[i]<<" ";cout<<endl;
// fo(i,0,mod-1) cout<<A.f[i]<<" ";cout<<endl;
// }
// a.chen(A);
qpower(n-1);
// if (s==2)
// {
// fo(i,0,mod-1) cout<<a.f[i]<<" ";cout<<endl;
// fo(i,0,mod-1) cout<<A.f[i]<<" ";cout<<endl;
// }
ans[s]=(ans[s]+a.f[v])%ansmod;
}
return;
}
bz[len-t]=0;
dfs(t+1,s<<1);
bz[len-t]=1;
dfs(t+1,(s<<1)+1);
}
void Dfs(int t)
{
int i,j,s1=0,s2=0,bz=1;
if (t>=len)
{
fd(i,len-1,0)
{
switch (d[i])
{
case 0:{
s1=(s1<<1);
s2=(s2<<1);
break;
}
case 1:{
s1=(s1<<1)+1;
s2=(s2<<1);
bz=-bz;
break;
}
case 2:{
s1=(s1<<1)+1;
s2=(s2<<1)+1;
break;
}
}
}
if (s1>s2)
ans[s1]=(ans[s1]+ans[s2]*bz)%ansmod;
return;
}
fd(i,2,0)
{
d[t]=i;
Dfs(t+1);
}
}
void DFS(int t,int s)
{
int i;
if (t>len)
{
if (s)
{
fd(i,len-1,0)
if (bz[i])
printf("%d",i);
printf(" ");
printf("%d\n",(ans[s]+ansmod)%ansmod);
}
return;
}
bz[len-t]=0;
DFS(t+1,s<<1);
bz[len-t]=1;
DFS(t+1,(s<<1)+1);
}
int main()
{
// freopen("a.in","r",stdin);
// freopen("b.out","w",stdout);
// freopen("S8_2_2.in","r",stdin);
scanf("%d%d%d%d",&n,&len,&mod,&v);
Len=len;
dfs(1,0);
Dfs(0);
DFS(1,0);
}