BZOJ 1025: [SCOI2009]游戏

来源:互联网 发布:跳跃网络次元大作战 编辑:程序博客网 时间:2024/06/08 09:05

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1025


思路:首先题目等价于将n拆成多个数相加,然后将这些数求lcm,所有的可能中,有多少个不同的lcm. 首先我们注意到对于a,b的lcm,我们假设将a,b质因子分解后,那么lcm的质因子是a和b的"并集"指数去a,b两个中更大的,那么对于小于n的数的素数,然后我们只需要统计小于n的素数的指数的情况就行了,我们可以让n=x1+x2+x3...+xi中的xi只等于素数的若干次方,这样是最极限的情况, 因为只需要x1+....+xi不大与n,我们可以用1来补 . 我们一个一个素数看,这个素数可以取,可以不取,也可以取若干个(保证不超过n), 那么我们用dp[n][rest] 表示前n个素数,当前剩下可取的数的和为rest的方案数. 然后就是简单的dp


代码:

#include <iostream>#include <cstdio>#include <cstring>#include <string.h>#include <queue>#include <vector>#include <algorithm>#include <cassert>#include <set>#include <map>#include <cmath>#include <ctime>using namespace std;#define rep(i,a,b) for(int i=(a);i<(b);++i)#define rrep(i,a,b) for(int i=(a);i>=(b);--i)#define clr(a,x) memset(a,(x),sizeof(a))#define eps 1e-8#define LL long long#define mp make_pairconst int maxn=1200+5;LL dp[210][maxn];vector<int> pe;bool ispe[maxn];int main(){    rep(i,0,maxn) ispe[i]=true;    rep(i,2,maxn) {        if(ispe[i]) {            pe.push_back(i);            for(int j=i+i;j<maxn;j+=i) ispe[j]=false;        }    }    int n;    while(scanf("%d",&n)==1) {        clr(dp,0);        dp[0][0]=1;        LL sum=0;        rep(i,0,pe.size()) {            int k=0,x=1;            if(pe[i]>n) {                rep(j,0,n+1) sum+=dp[i][j];                break;            }            while(x<=n) { ++k; x*=pe[i]; }            x /= pe[i];            --k;            rrep(j,n,0) {                int y=x; dp[i+1][j]+=dp[i][j];                rep(z,0,k) {                    if(j-y>=0) dp[i+1][j]+=dp[i][j-y];                    y /= pe[i];                }            }        }        printf("%lld\n",sum);    }}


0 0
原创粉丝点击