1. 程式人生 > >BZOJ 1025--遊戲(DP)

BZOJ 1025--遊戲(DP)

一個 def read 我們 long long ++ 公倍數 center fin

1025: [SCOI2009]遊戲

Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 2550 Solved: 1664
[Submit][Status][Discuss]

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
3 1 2 4 5 6
1 2 3 5 4 6
2 3 1 4 5 6
3 1 2 5 4 6
1 2 3 4 5 6
這時,我們就有若幹排1到N的排列,上例中有7排。現在windy想知道,對於所有可能的對應關系,有多少種可
能的排數。

Input

  包含一個整數N,1 <= N <= 1000

Output

  包含一個整數,可能的排數。

Sample Input

【輸入樣例一】
3
【輸入樣例二】
10

Sample Output

【輸出樣例一】
3
【輸出樣例二】
16

題目鏈接:

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

Solution

    置換的性質。。

    顯然在置換過程中會有幾個環,而排數則是每個環大小的公倍數。。

    於是DP一下有多少不同的公因數即可。。

代碼

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define N 200000
#define LL long long
using namespace std;
inline int Read(){
    int x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
int n,tot;
LL dp[1005],c[1005],pri[1005];
int main(){
    for(int i=2;i<=1005;i++){
        if(c[i]==0) pri[++tot]=i;
        for(int j=1;j<=tot&&pri[j]*i<=1005;j++){
            c[pri[j]*i]=1;
            if(i%pri[j]==0) break;
        }
    }
    scanf("%d",&n);
    for(int i=0;i<=n;i++) dp[i]=1;
    for(int i=1;i<=tot;i++){
        for(int k=n;k>=pri[i];k--){
            for(int j=pri[i];j<=k;j*=pri[i]){
                dp[k]+=dp[k-j];
            }
        }
    }
    printf("%lld\n",dp[n]);
    return 0;
}

  

  

This passage is made by Iscream-2001.

BZOJ 1025--遊戲(DP)