1. 程式人生 > >洛谷 P2401 不等數列

洛谷 P2401 不等數列

ace scan += esp cpp 左右 -i 明顯 LG

其實有兩種方法來解這道題

第一種:找規律(非正經

技術分享圖片
一看,這玩意像是個楊輝三角,還左右對稱呢

因為新插入一個數$n$,有$n+1$個位置可以選,所以總數就乘$n+1$,對應的$f[n+1][i]$也就等於$f[n][i]$了大概。可是一看,不大對,好像不是這樣。那麽就像,反正加一個數要麽沒變,要麽加一個小於號,那麽不在$f[n+1][i]$的一定是分到了$f[n+1][i+1]$裏去了。那麽以$n=3$時為例,$f[3][1]4=4,f[4][1]=1$也就是接收了$1$倍的$f[3][1]$。那麽就有$3$個分到$f[4][2]$裏去了。$f[3][2]4=16,f[4][2]=11$,而$f[4][2]$已經有$3$個,那麽就接收了來自$f[4][2]$的$8$個,也就是$2$倍的$f[3][2]$。······以此類推,大概就得出了$f[n+1][i]+=f[n][i](i+1),f[n+1][i+1]+=f[n][i]

(n-i)$的規律

-----------------------------------------------手動分割線------------------------------------------------

第二種:數學方法推

這是正經方法

前面說過,加入一個數$n$,有$n$+$1$個位置可以選,可以插在兩旁或者不等號的位置,因為新插入的數一定是最大的,所以插在最左邊多一個大於號,而插在最右邊多一個小於號。

那麽問題來了,如果插在不等號的位置呢?

首先,明確一下,插入在不等號位置後,一個不等號會變為兩個不等號,由於新插入的數一定是最大的,所以這兩個不等號中前面的一定是小於號,後面的一定是大於號。那麽就很明顯了,如果這個位置原來是小於號,那麽插入$n$之後,小於號數不變;如果原來是大於號,那麽插入$n$之後,小於號數+$1$。那麽原本有$i$個數$j$個小於號,加上一個數後便會有$j+1$種小於號不變$i-j$種小於號$+1$的情況。

上代碼

先是暴力版(通不過的,這是幫助我打出那張圖的版本)

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=1005;
int f[maxn],n,ans[maxn];
bool s[maxn];
void dfs(int step){
    if(step>n){
        int sum=0;
        for(int i=1;i<n;i++)sum+=f[i]<f[i+1]?1:0;
        ans[sum]++;
        return
; } for(int i=1;i<=n;i++) if(!s[i]){ s[i]=1; f[step]=i; dfs(step+1); s[i]=0; } } int main(){ scanf("%d",&n); dfs(1); for(int i=0;i<n;i++)printf("%d ",ans[i]); }

然後上

正常版本

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=1005;
int n,k,f[maxn][maxn];
int main(){
    //freopen("num.in","r",stdin);
    //freopen("num.out","w",stdout);
    scanf("%d%d",&n,&k);
    if(k>(n-1)/2)k=n-k-1;
    f[1][0]=1;
    for(int i=1;i<n;i++){
        for(int j=0;j<=(i-1)/2;j++){//由於它類似於楊輝三角,左右對稱,所以只求左側就好
            f[i+1][j]=(f[i+1][j]+f[i][j]*(j+1))%2015;
            f[i+1][j+1]=(f[i+1][j+1]+f[i][j]*(i-j))%2015;
        }
        if(i%2==0)f[i+1][i/2]=(f[i+1][i/2]*2)%2015;
    }   
    printf("%d",f[n][k]);
    return 0;
}

不喜勿噴

請勿抄襲

洛谷 P2401 不等數列