TopCoder SRM 666 Div1 444 SumOverPermutations
阿新 • • 發佈:2018-12-15
感覺是道好題~TC好多題就這樣,想半天,然後程式碼幾行就完了。 原來碰到這種排列的dp就一臉懵逼,因為狀態特別難設計,每次都感覺只會狀壓,現在終於有點get到其中的套路了。
在這題裡我們可以發現幾個事實
- 每個位置對答案的貢獻只和它左右兩邊是否比它早確定有關
- 我們可以通過將插入到的排列中得到所有到的所有排列
於是我們可以弄一個表示到第個位置,這個位置在前個裡面是第個確定的,以及前一個位置是否比它早確定,表示早,表示晚。 轉移的話就列舉一下第個位置是第幾個被確定的。然後這樣複雜度還是爆炸,於是就加個字首和優化,再順便滾動陣列一下就過了。
然而,我一開始T了!!!震驚,說好的TC一秒1e9呢(霧),欺騙感情!! 結果發現是我手動取模爆炸了。。。。。。改了就過了。。。。。。
#include <bits/stdc++.h>
#define fr(i,x,y) for(int i=x;i<=y;i++)
#define ll long long
using namespace std;
const int N=4001;
const int p=1e9+7;
ll f[2][N] [2];
template<class T> void checkmin(T &a,const T &b) { if (b<a) a=b; }
template<class T> void checkmax(T &a,const T &b) { if (b>a) a=b; }
class SumOverPermutations {
public:
int findSum( int n ) ;
};
void Add(ll &x,ll y){
x+=y;
while(x<0) x+=p;
while (x>=p) x-=p;
}
int SumOverPermutations::findSum(int n) {
int cur=1;
f[1][1][1]=1;
fr(o,2,n){
cur^=1;
//memset(f[cur],0,sizeof f[cur]);
fr(i,1,o){
f[cur][i][0]=f[cur][i][1]=0;
Add(f[cur][i][0],(n-1)*f[cur^1][i-1][0]%p+n*f[cur^1][i-1][1]%p);
Add(f[cur][i][1],(n-2)*(f[cur^1][o-1][0]-f[cur^1][i-1][0])%p);
Add(f[cur][i][1],(n-1)*(f[cur^1][o-1][1]-f[cur^1][i-1][1])%p);
}
if (o==n) continue;
fr(i,1,o){
Add(f[cur][i][0],f[cur][i-1][0]);
Add(f[cur][i][1],f[cur][i-1][1]);
}
}
ll ans=0;
fr(i,1,n){
Add(ans,f[cur][i][0]*(n-1)%p);
Add(ans,f[cur][i][1]*n%p);
}
return ans;
}