标签:多重背包 开始 算法 置换群 本质 这一 break sharp 左右
Description:
windy学会了一种游戏。
对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应。
最开始windy把数字按顺序1,2,3,……,N写一排在纸上。
然后再在这一排下面写上它们对应的数字。
然后又在新的一排下面写上它们对应的数字。
如此反复,直到序列再次变为1,2,3,……,N。
如: 1 2 3 4 5 6
对应的关系为
1->2 2->3 3->1 4->5 5->4 6->6
windy的操作如下
1 2 3 4 5 6
2 3 1 5 4 6
3 1 2 4 5 6
1 2 3 5 4 6
2 3 1 4 5 6
3 1 2 5 4 6
1 2 3 4 5 6
这时,我们就有若干排1到N的排列,上例中有7排。
现在windy想知道,对于所有可能的对应关系,有多少种可能的排数。
Hint:
n<=1000
Solution:
所谓的对应关系就是置换。
开始想到置换群,发现不能直接转化。
思考为什么会重复回来,因为,向每一个置换的位置连一条有向边,
n个点n条边,并且每个点必然一个入度一个出度,所以一定连出来若干个环。
发现,环长就是这个环上的点重复一次的排数
所以,排数就是lcm(L1,L2,L3,L4...Lk)+1了。
而由于∑Li=n,所以,所有的L其实就是n的一个拆分。
那么答案就是,n的所有正整数拆分中,拆分的所有数的不同的lcm有几个。
但是n的拆分太多太多了。。。这种算法也就算到n=50就不行了。
无法继续考虑。
正难则反。
考虑凑出多少个不同的lcm不行的话,
就钦定一个数m是lcm,看能不能拼出来。
m显然无法枚举。那就考虑m作为lcm是怎么来的。
我们把m质因数分解一下,
m=p1^q1*p2^q2*...pk^qk
那么,由于lcm是所有的数中质因数分解的所有质数指数取一个max,
这些原来的拆分的数中,分别质因数分解,质数指数的max就分别是:q1,q2...qk
所以,只要判断p1^q1+p2^q2+...+pk^qk<=n是否成立即可。
若成立,那么m就是一个合法可以拼凑的lcm
(相当于,我们只取这些质数的最大指数,作和,剩下的全部取1。
反正对于lcm=m来讲,取其他的数,也都是被max埋没了。)
我们的问题就转化成:p1^a1+p2^a2+..+pl^al<=n的解的个数。(对于每一个不同的a的选择,就对应一种lcm)
(其中,pl就是最大的小于n的质数)
然后就是多重背包啦!
物品上限,只要pk^ak不要超过n即可,基本没有几件。
复杂度:O(N^2)左右
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1000+5; int pri[N],tot; ll f[N]; bool vis[N]; int n; void sieve(){ for(int i=2;i<=n;i++){ if(!vis[i]){ pri[++tot]=i; } for(int j=1;j<=tot;j++){ if(pri[j]*i>n) break; vis[pri[j]*i]=1; if(i%pri[j]==0) break; } } } int main() { scanf("%d",&n); sieve(); f[0]=1; for(int i=1;i<=tot;i++) for(int j=n;j>=0;j--){ for(int k=pri[i];k<=j;k*=pri[i]){ f[j]+=f[j-k]; } } ll ans=0; for(int i=0;i<=n;i++)ans+=f[i]; printf("%lld",ans); return 0; }
总结:
还是正难则反没有想到啊。之前都想到了。
卡在了自然数拆分的方案怎么统计。。。
有时候,直接求拼凑的方案等无法处理,
就考虑反着来,这个方案能否被拼凑。
二分答案本质就是这个思路。
相当于,我不知道答案求答案,和我猜一个答案验证一下。
标签:多重背包 开始 算法 置换群 本质 这一 break sharp 左右
原文地址:https://www.cnblogs.com/Miracevin/p/9419195.html