zoukankan      html  css  js  c++  java
  • [SCOI2009]游戏

    链接

    [SCOI2009]游戏

    题解

    先把图建出来,容易发现这是一张由点和环构成的图,每个环转回去需要的步数就是环的长度,多个环同时转回去的最小长度为(lcm(len_1, len_2, len_3, ... , len_n))
    又环的长度和为(n),问题可转化成把一个正整数(n)分解成若干数的和,求他们的(lcm)的可能方案数
    (lcm)分解质因数,考虑一堆数的(lcm)是他们出现过的质因数的最高次幂的乘积,为了不产生损耗,构造的时候直接用质数的幂来凑,这样(gcd(..) = 1),不会产生损耗
    注意他们的和可以小于(n),因为剩下的可以用(1)补齐
    于是问题转化为一个背包问题,设(dp[i][j])表示用了(i)个质数,总和为(j)的总方案数,(dp[i][j] = sum f[i - 1][j - p_i^k])

    代码

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N = (int)1e3 + 10;
    int n;
    int prime[N], tot, f[N], ans[N];
    bool vis[N];
    void Prime (int n) {
    	for (register int i = 2; i <= n; ++i) {
    		if (!vis[i]) prime[++tot] = i;
    		for (register int j = 1; j <= tot; ++j) {
    			if (prime[j] * i > n) break;
    			vis[i * prime[j]] = 1;
    			if (i % prime[j] == 0) break;
    		}
    	}
    }
    signed main() {
    	cin >> n;
    	if (n == 1) return cout << 1, 0;
    	Prime(n);
    	ans[0] = 1;
    	for (register int i = 1; i <= tot; ++i) 
    		for (register int j = n; j >= prime[i]; --j) {
    			int tmp = prime[i];
    			while (tmp <= j) {
    				ans[j] += ans[j - tmp];
    				tmp *= prime[i];
    			}
    		}
    	ans[0] = 0;
    	for (register int i = 1; i <= n; ++i) ans[0] += ans[i];
    	printf("%lld", ans[0] + 1);
    	return 0;
    }
    
  • 相关阅读:
    Python 函数
    jQuery的选择器中的通配符
    Spring thymeleaf
    Mybatis 映射关系
    Spring Security学习笔记
    Python中的魔术方法
    Python enumerate
    python lambda表达式
    Vue自定义指令完成按钮级别的权限判断
    elemetUI开关状态误操作
  • 原文地址:https://www.cnblogs.com/kma093/p/13395252.html
Copyright © 2011-2022 走看看