题目大意
给出长度为m的数组s和数字N,求多少个数k满足0<=k<N且对于每个i=0~m-1,都有gcd(k+i,N)=1当且仅当si=1
m<=40,N以Πpi^ai的方式给出,n<=5e5
题解
先把01翻转变成在x%p=0的x处填1,填出来的显然按照Πpi为一个周期,所以只需要考虑ai=1的情况最后再乘上Πpi^(ai-1)即可
数字k可以写成模pi的同余组,一个同余组唯一对应一个0~N-1中的数,否则存在<N的%pi=0的数,所以唯一对应
问题变成统计同余组的情况,对于%p=q相当于在数组上按照间隔p的顺序跳着填,类似01010101或者01001001之类的
于是对于p<=m的状压记忆化,>m的因为只会填最多一个所以可以只记录剩余个数dp
发现当p以3或5开头的话状态很多,同时发现当p=29,31,37的时候很类似上面第二部分的dp,所以在做29,31,37的时候把前后m-p位状压中间的记录个数即可,<=23的记忆化,>40的记个数
分三个部分dp,听起来很简单但是细节很多
细节:
1、记忆化23的时候如果用map存时间会炸掉(大概一千七百万多),所以在做23的时候直接转移到第二部分
2、第二部分做29时如果直接循环复杂度为2^22*18*11,所以只做有值的部分,时间变成17000000*11
3、做完29之后状态会增多,如果再按照上面的来搞状态就不止一千多万了,所以第二部分每做完之后都要缩成新的二进制状态
4、缩完之后空间直接存会炸掉(2^22*41),所以要编号
5、缩的时候新开的数组开2^18*23,开原来那么大也会炸掉
code
不知道有没有更简单的做法
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define low(x) ((x)&-(x))
#define add(a,b) a=((a)+(b))%1000000007
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define mod 1000000007
#define ll long long
//#define file
using namespace std;
int g[79691777],G[6029313],h[41],num[1048576],m,n,M,MM,M2,MM2,id,id2,i,j,k,l,J,K,sum;
ll p[500001],P[41],A,L,L2,L3,LL2,ans,Ans,s1,s2,S1,S2,S;
char st[41];
pair<ll,int> s;
map<ll,int> f[13];
map<ll,int> :: iterator I;
ll qpower(ll a,int b) {ll ans=1; while (b) {if (b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;} return ans;}
int turn(int i,int j,int k,int M,int L2) {return (i*(L2+1)+j)*(M+1)+k;}
ll get(ll t,int x,int y)
{
int i,ans=0;
t>>=x;y-=x-1;
while (y)
{
if (y>20) ans+=num[t&(P[20]-1)],y-=20,t>>=20;
else {ans+=num[t&(P[y]-1)];break;}
}
return ans;
}
int main()
{
#ifdef file
freopen("CF765G.in","r",stdin);
#endif
P[0]=1;
fo(i,1,40) P[i]=P[i-1]*2;
scanf("%s",st+1);m=strlen(st+1);Ans=1;
scanf("%d",&n);
fo(i,1,n) scanf("%lld%lld",&p[i],&A),Ans=(Ans*qpower(p[i],A-1))%mod;
fd(i,m,1) s1=s1*2+(st[i]-'0'),sum+=!(st[i]-'0');
l=(1ll<<20)-1;
fo(i,1,l) num[i]=num[i-low(i)]+1;
sort(p+1,p+n+1);
L=(1ll<<m)-1;s1^=L;
if (p[1]<=23)
f[0][0]=1;
else
if (p[1]<m)
M=m-p[1],L2=P[M]-1,g[get(s1,M,p[1]-1)]=1;
else
h[sum]=1;
l=1;
while (l<=n && p[l]<=23)
{
for (I=f[l-1].begin(); I!=f[l-1].end(); ++I)
{
s=*I;
for (i=S=0; i<m; i+=p[l]) S|=1ll<<i;
fo(j,0,p[l]-1)
{
s2=s.first|S;
if ((s2&s1)==s2)
{
if (l==n || p[l+1]>23)
{
if (l==n || p[l+1]>=m)
k=get(s2^s1,0,m-1),add(h[k],s.second);
else
{M=m-p[l+1];L2=P[M]-1;M2=p[l+1]-M;k=get(s2^s1,M,p[l+1]-1);add(g[turn(s2&(P[M]-1),s2>>p[l+1],k,M2,L2)],s.second);}
}
else
add(f[l][s2],s.second);
}
S=(S*2)&L;
}
}
++l;
}
if (!M && l<=n && p[l]<m) {printf("0
");return 0;}
while (l<=n && p[l]<m)
{
S=get(s1,M,p[l]-1);S1=s1&(P[M]-1),S2=s1>>p[l];
fd(i,L2,0)
{
fd(j,L2,0)
{
fo(k,0,M2)
{
id=turn(i,j,k,M2,L2);
if (g[id])
{
s2=g[id];g[id]=0;
if (l==n || p[l+1]>=m)
{
fo(J,0,M-1)
if ((s1&P[J]) && (s1&P[J+p[l]]))
K=num[(i|P[J])^S1]+num[(j|P[J])^S2]+k,add(h[K],s2);
if (k)
K=num[i^S1]+num[j^S2]+k-1,add(h[K],1ll*s2*k%mod);
K=num[i^S1]+num[j^S2]+k,add(h[K],1ll*s2*(S-k)%mod);
}
else
{
fo(J,0,M-1)
if ((s1&P[J]) && (s1&P[J+p[l]]))
add(g[turn(i|P[J],j|P[J],k,M2,L2)],s2);
if (k)
add(g[turn(i,j,k-1,M2,L2)],1ll*s2*k%mod);
add(g[turn(i,j,k,M2,L2)],1ll*s2*(S-k)%mod);
}
}
}
}
}
++l;
if (l<=n && p[l]<m)
{
MM=m-p[l],LL2=P[MM]-1,MM2=p[l]-MM;
S1=get(s1,MM,M-1);S2=get(s1,p[l-1],p[l]-1);
fo(i,0,L2)
{
fo(j,0,L2)
{
fo(k,0,M2)
{
id=turn(i,j,k,M2,L2);
if (g[id])
{
id2=turn(i&(P[MM]-1),j>>(p[l]-p[l-1]),k+(S1-(num[i]-num[i&(P[MM]-1)]))+(S2-(num[j]-num[j>>(p[l]-p[l-1])])),MM2,LL2);
add(G[id2],g[id]);
}
}
}
}
memcpy(g,G,((LL2+1)*(LL2+1)*(MM2+1))*4);
M=MM,L2=LL2,M2=MM2;
memset(G,0,((L2+1)*(L2+1)*(M2+1))*4);
}
}
while (l<=n)
{
fo(i,0,m)
{
if (i)
add(h[i-1],1ll*h[i]*i%mod);
h[i]=1ll*h[i]*(p[l]-m+(sum-i))%mod;
}
++l;
}
ans=h[0];
printf("%lld
",ans*Ans%mod);
fclose(stdin);
fclose(stdout);
return 0;
}