【dp】51nod
阿新 • • 發佈:2019-02-09
#include <cstdio> #include <cstring> using namespace std; /* 51nod - 1020 逆序排列 對於一個有n個數的序列,是由有n-1個數的序列再添上一個n組成,n添在哪個部位,就決定了狀態的轉移。 dp[i][j] 代表有i個數的序列,逆序列值為j的個數。 dp[i][j] = sum(dp[i-1][(j-i+1)~j]); 如此來三層for,自然轉換一下,記錄上個狀態的字首和,本來想開個pre[1010][20004]的陣列,既然開不了,那麼就換成滾動陣列 就好了,反正不需要記錄這個過程的值。 參閱了其他coder的程式碼,其實遞推式可以進一步推: dp[i][j] = sum(dp[i-1][(j-i+1)~j]); dp[i][j-1] = sum(dp[i-1][(j-i)~(j-1)]); 兩式相減:dp[i][j] = dp[i][j-1] + dp[i-1][j] - dp[i-1][j-i]; */ // code 1 const int mod = 1e9+7; int dp[1010][20004]; int pre[2][20004]; int main(){ memset(dp,0,sizeof(dp)); dp[1][0] = 1; for(int j = 0; j<=20000; j++) pre[1][j] = 1; for(int i = 2; i<=1000; i++){ for(int j = 0; j<=20000; j++){ int now = i%2; int pos = (i-1)%2; dp[i][j] = (pre[pos][j]-(j-i<=0?0:pre[pos][j-i]))%mod; if(!j) pre[now][j] = dp[i][j]; else pre[now][j] = (pre[now][j-1]+dp[i][j])%mod; } } int T; scanf("%d",&T); while(T--){ int n,k; scanf("%d%d",&n,&k); printf("%d\n",(dp[n][k]+mod)%mod); } return 0; } // code 2 const int mod = 1e9+7; int dp[1010][20004]; int main(){ memset(dp,0,sizeof(dp)); for(int i = 1; i <= 1000; i++){ dp[i][0] = 1; for(int j = 1; j<=(i*(i-1))/2 && j<=20000; j++){ if(j >= i) dp[i][j] = ((dp[i][j-1]+dp[i-1][j]-dp[i-1][j-i])%mod + mod)%mod; else dp[i][j] = (dp[i][j-1]+dp[i-1][j])%mod; //printf("%d %d %d\n",i,j,dp[i][j]); } } int T; scanf("%d",&T); while(T--){ int n,k; scanf("%d%d",&n,&k); printf("%d\n",(dp[n][k]+mod)%mod); } return 0; }