bzoj1025: [SCOI2009]游戏(DP)

  题目大意:将长度为n的排列作为1,2,3,...,n的置换,有可能置换x次之后,序列又回到了1,2,3,...,n,求所有可能的x的个数。

  看见这种一脸懵逼的题第一要务当然是简化题意。。。我们可以发现,序列回到原状的次数就是每个循环的规模(即在循环中的数字个数)的lcm,而且因为有n个数,显然所有循环的规模之和就是n,那么问题就被简化成了a1+a2+a3+...+ak=n,求lcm(a1,a2,a3,...,an)的个数。

  现在题意已经清楚多了,那咋写呢QAQ

  我们把一个数分解质因数,p为质数,那么A=p1^m1*p2^m2*p3^m3*...*ph^mh,我们令a1=p1^m1,a2=p2^m2,...,ah=ph^mh,易证a1+a2+a3+...+ah<=n(分<和=两种情况讨论),则A为一个可行解。

  于是问题又变成了求有多少种a1+a2+a3+...+ah<=n。

  即有多少种(m1,m2,m3,...,mh)使p1^m1+p2^m2+p3^m3+...+ph^mh<=n。

  令f[i][j]为前i个质数,p1^m1+p2^m2+p3^m3+...+pi^mi和为j的方案数,则有:

  f[i][j]=f[i-1][j]【这个质数不用】+sigma(f[i-1][j-p[i]^k])【j-p[i]^k>=0】

  tot为n以内的质数个数,则答案为sigma(f[tot][i])【0<=i<=n】

代码如下:

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#define ll long long
using namespace std;
ll f[1010][1010],ans;
int n,p[1010],tot;
bool v[1010];
int main()
{
    scanf("%d",&n);
    for(int i=2;i<=n;i++)
    if(!v[i])
    {
        p[++tot]=i;
        for(int j=2;j*i<=n;j++)v[i*j]=true;
    }
    f[0][0]=1;
    for(int i=1;i<=tot;i++)
    for(int j=0;j<=n;j++)
    {
        f[i][j]=f[i-1][j];
        for(int k=1,sum=1;j-sum*p[i]>=0;k++)
        {
            sum*=p[i];
            f[i][j]+=f[i-1][j-sum];
        }
    }
    for(int i=0;i<=n;i++)
    ans+=f[tot][i];
    printf("%lld\n",ans);
}

时间: 2024-11-03 21:34:16

bzoj1025: [SCOI2009]游戏(DP)的相关文章

BZOJ1025: [SCOI2009]游戏

1025: [SCOI2009]游戏 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2029  Solved: 1315[Submit][Status][Discuss] Description windy学会了一种游戏.对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应.最开始windy把数字按顺序1,2,3,……,N写一排在纸上.然后再在这一排下面写上它们对应的数字.然后又在新的一排下面写上它们对应的数字.如此反复,直到序列再次变为1,

bzoj1025 [SCOI2009]游戏——因数DP

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1025 这篇博客写得真好呢:https://www.cnblogs.com/phile/p/4473192.html 代码如下: #include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,pri[1005],cnt; long long f[1005][1005]

[BZOJ1025] [SCOI2009]游戏 解题报告

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

[bzoj1025][SCOI2009]游戏 (分组背包)

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

bzoj 1025 [SCOI2009]游戏 dp

题面 题目传送门 解法 显然,可以回到初始状态就意味着一定由若干个环组成 假设环的长度为\(l_i\) 那么,我们可以得到\(\sum l_i=n\) 不考虑自环的情况,那么\(\sum l_i≤n\) 将\(n\)以内的质因数全部筛出,强制每一次只取某一个质数的次幂,那么就可以解决重复计数的问题 时间复杂度:\(O(n^2)\) 代码 #include <bits/stdc++.h> #define int long long #define N 1010 using namespace s

BZOJ 1025: [SCOI2009]游戏( 背包dp )

显然题目要求长度为n的置换中各个循环长度的lcm有多少种情况. 判断一个数m是否是满足题意的lcm. m = ∏ piai, 当∑piai ≤ n时是满足题意的. 最简单我们令循环长度分别为piai,不足n的话,我们令其他循环长度为1, 补到=n为止. 这样它们的lcm显然是=m的. 然后就是一个背包了...dp(i, j) = dp(i - 1, j) + ∑1≤t≤adp( i - 1, j - pt ) 表示前i个质数, 和为j有多少中方案 #include<bits/stdc++.h>

SCOI2009游戏

1025: [SCOI2009]游戏 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1065  Solved: 673[Submit][Status] Description windy学会了一种游戏.对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应.最开始windy把数字按顺序1,2,3,……,N写一排在纸上.然后再在这一排下面写上它们对应的数字.然后又在新的一排下面写上它们对应的数字.如此反复,直到序列再次变为1,2,3,……,N.

【BZOJ 1025】 [SCOI2009]游戏

1025: [SCOI2009]游戏 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 1273  Solved: 805 [Submit][Status] Description windy学会了一种游戏.对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应.最开始windy把数字按顺序1,2,3,--,N写一排在纸上.然后再在这一排下面写上它们对应的数字.然后又在新的一排下面写上它们对应的数字.如此反复,直到序列再次变为1,2,3,--,N

[LuoguP1005]矩阵取数游戏 (DP+高精度)

题面 传送门:https://www.luogu.org/problemnew/show/P1005 Solution 我们可以先考虑贪心 我们每一次都选左右两边尽可能小的数,方便大的放在后面 听起来挺OK的 实则并不OK 反例: 3 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 如果贪心的话,我们会优先把右边那一串2先选了,再去选3和1 但是正确答案显然是先把3和1选了,再去选那一串2 既然贪心不成,我们可以考虑一下DP 然后我们考虑这样一个状态: f[i][j][k] 表示第i