BZOJ 3462 DZY Loves Math II

本文详细解析了一道涉及质因子、完全背包算法及组合数学的难题,通过逐步优化策略,从初步筛选质因子到利用完全背包算法解决大规模问题,最终通过优化背包算法和组合数计算得出解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

 
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.

转载于:https://www.cnblogs.com/bilibiliSmily/p/11120445.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值