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;
    }
    

      

  • 相关阅读:
    Gremlin基本使用
    SpringData JdbcTemplate Jdbc使用简介
    DOS命令行使用pscp实现远程文件和文件夹传输(转)
    vscode:让文件支持右键vscode打开
    vue-webpack项目本地开发环境设置代理解决跨域问题
    VueJS中学习使用Vuex详解
    Object.create()和new 创建对象的区别
    vue组件和插件的区别
    创建vue组件与自定义一个vue组件时的区别
    [Vue] : 自定义指令
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4319996.html
Copyright © 2011-2022 走看看