题意:n个格子,m个球,让你把球放入某些格子里,使得所有有球的格子之间的距离(abs(i-j))均为素数 ,让你输出方案数。
只占一个格子或者两个格子显然可行。
占有三个格子的情况下,则必须保证其中两者的间距为2,另两者的间距为一个+2以后仍为素数的素数。这个可以预处理。
占有四个格子的情况下,间距只有一种合法情况 2 3 2。
其他情况都不合法。
确定了占有的格子数,尝试放球保证没有一个格子为空的时候,可以用挡板法。
#include<cstdio> using namespace std; typedef long long ll; const ll MOD=1000000007ll; int T; ll n,m,ans,in2,in6; bool notprime[100005]; int primes[100005],pr,prime2[100005],p2; ll Quick_Pow(ll a,ll p){ if(p==0ll){ return 1ll; } ll res=Quick_Pow(a,p>>1); res=res*res%MOD; if((p&1ll)==1ll){ res=a%MOD*res%MOD; } return res; } int main(){ //freopen("j.in","r",stdin); in2=Quick_Pow(2ll,MOD-2ll); in6=Quick_Pow(6ll,MOD-2ll); int zu=0; notprime[1]=1; for(int i=2;i<=100000;++i) if(!notprime[i]){ primes[++pr]=i; for(ll j=(ll)i*(ll)i;j<=100000ll;j+=(ll)i){ notprime[j]=1; } } for(int i=1;i<=pr;++i){ if(!notprime[primes[i]+2]){ prime2[++p2]=primes[i]; } } scanf("%d",&T); for(;T;--T){ printf("Case %d: ",++zu); scanf("%lld%lld",&n,&m); ans=(ll)n; if(m>1)for(int i=1;i<=pr && n-primes[i]>0;++i){ ans=(ans+(ll)(n-primes[i])*(ll)(m-1)%MOD)%MOD; } if(m>2)for(int i=1;i<=p2 && n-prime2[i]-2>0;++i){ ans=(ans+(ll)(n-prime2[i]-2)*(ll)(m-1)%MOD*(ll)(m-2)%MOD*in2%MOD*2ll%MOD)%MOD; } if(n>7 && m>3){ ans=(ans+(ll)(n-7)*(ll)(m-1)%MOD*(ll)(m-2)%MOD*(ll)(m-3)%MOD*in6%MOD)%MOD; } printf("%lld ",ans); } return 0; }