zoukankan      html  css  js  c++  java
  • [BZOJ 1025] [SCOI2009] 游戏 【DP】

    题目链接:BZOJ - 1025

    题目分析

    显然的是,题目所要求的是所有置换的每个循环节长度最小公倍数的可能的种类数。

    一个置换,可以看成是一个有向图,每个点的出度和入度都是1,这样整个图就是由若干个环构成,这些环的长度和为 n 。

    因此,就是要求出和为 n 的正整数的最小公倍数的可能情况。

    有一个性质:这些正整数中有合数存在的最小公倍数,都可以用全是质数的情况包含。

    所以我们只要求出用质数组成的情况就可以了。我们要求的就是,若干个质数,它们的和小于等于 n,它们的最小公倍数情况。

    先筛法求出 n 以内的所有素数。然后使用 DP:

    f[i][j] 表示前 i 个素数之内,组成的和为 j ,LCM 的种类数。

    f[i][j] = f[i - 1][j] + sigma(f[j - Prime[i]^k])

    初始状态是 f[0][0] = 1

    当一些质数的和不同的时候,它们的积一定不同。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    
    using namespace std;
    
    const int MaxN = 1000 + 5;
    
    int n, Top;
    int Prime[MaxN];
    
    bool isPrime[MaxN];
    
    typedef long long LL;
    LL Ans;
    LL f[MaxN][MaxN];
    
    int main()
    {
    	scanf("%d", &n);
    	for (int i = 1; i <= n; ++i) isPrime[i] = true;
    	isPrime[1] = false; Top = 0;
    	for (int i = 2; i <= n; ++i) 
    	{
    		if (isPrime[i]) Prime[++Top] = i;
    		for (int j = 1; j <= Top && i * Prime[j] <= n; ++j) 
    		{
    			isPrime[i * Prime[j]] = false;
    			if (i % Prime[j] == 0) break;
    		}
    	}
    	f[0][0] = 1;
    	for (int i = 1; i <= Top; ++i) 
    	{
    		for (int j = 0; j <= n; ++j) f[i][j] = f[i - 1][j];
    		for (int j = 0; j <= n; ++j) 
    			for (int k = Prime[i]; k <= n - j; k *= Prime[i])
    				f[i][j + k] += f[i - 1][j];
    	}
    	Ans = 0;
    	for (int i = 0; i <= n; ++i) Ans += f[Top][i];
    	printf("%lld
    ", Ans);
    	return 0;
    }
    

      

  • 相关阅读:
    java 对象属性复制,将一个对象的属性值赋值给另一个对象, 属性名需要相同
    文件上传设置上传文件大小
    layui form.on('select(xxx)',function(){});绑定失败
    列表显示, 内容过长省略显示, 鼠标停留在内容上显示全部内容
    mybatis : ERROR. token : COMMA, pos : 373
    js判断手机系统
    vue v-nav指令属性列表
    第五节 tensorboard可视化
    第四节 生成随机张量和张量合并
    第三节 张量
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4319996.html
Copyright © 2011-2022 走看看