题目描述
2<=S<=2*10^6,1<=n<=10^18,1<=q<=10^5
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
看见这个n的范围
我先嘤嘤嘤为敬
开始我的骗分历程
1. 可怜的10分
我们可以发现若要满足 {p1,p2,...,pn} 的 lcm 为 s
那么 p 一定是 s 的质因子 <这××不是废话嘛啊喂>
所以加上 ! ( s % p ) 的限制条件筛出来并存在vector wtf中
记总数为k
现在我们开始骗分了 <OIer的分能叫骗吗?>
记 fu = p1 * p2 * ... * pk
如果 fu != s 对于每一组puts("0")就玩事儿了
<好了题解结束>
2. 光荣的20分
我们发现 n 并不大 <不大个鬼啊(王某猿呸源y音)>
只有10 ^ 18
所以我们考虑对 n 进行骗分呸算法
我们有一个 wtf vector 容器存的所有质因子
对,聪(*)明(*)的读者已经想到 这是一个完全背包的裸题
恭喜你 你已经骗到了所有的分数
但是更加睿智的读者会说 n特别大啊喂
没关系没关系(whs音)
不超long long
用一个神奇的map不就行了?
就是这样
好了题解又结束了
开始我的正(si)解(wang)历程
//记一个k大小数列{pick1,pick2,pick3,...,pickk}
//表示对于由S得到的每一个pi(共k个)分别选择了picki次
//不妨设(QAQ 我没想到啊(荣起大哥音)! ) picki = x*(s/pi)+y;
//那么对于每一次x or y的改变 分别对应着一个方案
//我们发现 对于每一个 x 变化量为 1 时(就是x+1)
//picki 多了 s/pi 次
//故 pi*picki 的变化量为s
//即 对于x++时,占用了s的体积
//可以得到 x 的总量为 n/s (记为m)
//所以我们可以对所有的 pick 分配 x
//方案数为对于 k 个盒子共放 x 个球
//根据隔板法
//方案总数为
//C(m+k−1,k−1) (这总不用解释吧QwQ)
//---------------------------------
//现在考虑y
//y已经很小了(远远小于n啊喂)
//进行背包即可
//根据乘法原理 不难看出 x and y 是互相独立的事件( 可以理解为当分配完 x 后,对剩下的 y 的和即 n-(n/s)[向下取整了]*s 再进行不同与 x 的操作)
//故分别对于 x and y 进行方案数计算 cal(x)*cal(y)%mod 即为所求
//背包的话 很简单的啦
//设剩下的空间为 room
//即是用所有pi的集合{p1,p2,...,pk}
//填满 room 大小的背包
//完全背包(是了吧),完全背包(对了吧)<某志老师>
然而并不是......
这只是大体思路<本juruo就是死这儿的 |Orz<—>
我们还需要枚举没一个x对于每一个x进行背包
而且听mikufun大神说
背包有重复情况
我哇的一声哭了 自抱自泣
还是要坚强
QAQ
当我完成以后
发现我在用mod=1e9+7做lucas
我疯了
一个组合数又调一节课
处理k的逆元啥的 o(k)当场计(qu)算(shi)就完了

湖中月是天上月 眼前人似心上人
1 #include<vector> 2 #include<cstdio> 3 #include<cstring> 4 #define ll long long 5 using namespace std; 6 #define QAQ 2000005 7 #define mod 1000000007 8 ll prime[QAQ],primesize,phi[QAQ]; 9 bool isprime[QAQ]; 10 ll fac[10],inv[10]; 11 ll f[2][17000005]; 12 vector<long long>wtf; 13 ll T,s,maxn,m,k,y,ans; 14 ll n; 15 inline void getlist(ll listsize){ 16 memset(isprime,1,sizeof(isprime)); 17 isprime[1]=false; 18 for(ll i=2;i<=listsize;i++){ 19 if(isprime[i])prime[++primesize]=i; 20 for(ll j=1;j<=primesize&&i*prime[j]<=listsize;j++){ 21 isprime[i*prime[j]]=false; 22 if(i%prime[j]==0)break; 23 } 24 } 25 for(ll i=1;i<=listsize;i++){ 26 if(isprime[i]&&!(listsize%i))wtf.push_back(i); 27 } 28 } 29 inline int play(){ 30 int now=0,pre=1; 31 memset(f[now],0,sizeof f[now]); 32 f[now][0]=1; 33 for(ll i=0;i<wtf.size();i++){ 34 now^=1;pre^=1; 35 memset(f[now],0,sizeof f[now]); 36 ll up=s/wtf[i]-1; 37 for(ll j=0;j<wtf[i];j++){ 38 ll presum=0; 39 for(ll k=0;k<(s*wtf.size()/wtf[i]);k++){ 40 presum+=f[pre][k*wtf[i]+j]; 41 presum%=mod; 42 if(k>=up+1)presum-=f[pre][(k-up-1)*wtf[i]+j]; 43 f[now][k*wtf[i]+j]=presum; 44 } 45 } 46 } 47 return now; 48 } 49 ll quick_fk_me(ll a,ll n){ 50 ll ans=1; 51 while(n){ 52 if(n&1) ans=ans*a%mod; 53 a=a*a%mod; 54 n>>=1; 55 } 56 return ans; 57 } 58 ll C(ll m,ll n){ 59 ll i,ret=1; 60 for(i=m;i>=m-n+1;i--) ret=(ll)ret*(i%mod)%mod; 61 for(i=1;i<=n;i++) ret=(ll)ret*inv[i]%mod; 62 return ret; 63 } 64 int main(){ 65 scanf("%lld%lld",&s,&T); 66 getlist(s); 67 k=wtf.size(); 68 bool judge=0; 69 ll fu=1; 70 ll sum=0; 71 for(ll i=0;i<wtf.size();i++) 72 fu*=wtf[i],sum+=wtf[i]; 73 for(ll i=1;i<=10;i++) 74 inv[i]=quick_fk_me(i,mod-2); 75 if(fu!=s)judge=1; 76 int now=play(); 77 while(T--){ 78 ans=0; 79 scanf("%lld",&n); 80 n-=sum,m=n/s,y=n-m*s; 81 if(judge)puts("0"); 82 else if(n<0)puts("0"); 83 else{ 84 for(int i=0;i<=min(k,m);i++){ 85 ans=(ans+f[now][i*s+y]*C(m-i+k-1,k-1)%mod)%mod; 86 //cout<<m-i+k-1<<" "<<k-1<<" "<<C(m-i+k-1,k-1)<<endl; 87 } 88 printf("%lld\n",(ans+mod)%mod); 89 } 90
Over.