P2513 [HAOI2009]逆序对数列
题意:
求1-n的排列中逆序对数为k的排列个数
首先20分暴力next_permutation qaq
正解:DP
以f[i][j]表示1-i的排列有j个逆序对的方案、
考虑转移:对于新来的i
肯定是由i-1转移过来的
那么因为是排列,i一定比1--i-1都大
所以考虑它插入的位置
比如1 2 3 4 现在要插入5
产生逆序对的个数等于插入位置后面的数的个数
所以,它的加入对答案的贡献是$\in (0,i-1)$的
因此,$f[i][j]=\sum_{p=0}^{i-1}f[i][j-p]$
可以用前缀和优化,sum记录j-i+1到j的f之和
随着j的增加,在加上当前的同时别忘了减去开头(sum的长度固定,为i-1)
#include<cstdio> #include<iostream> #include<cstring> #include<cctype> #include<algorithm> using namespace std; #define int long long #define olinr return #define _ 0 #define love_nmr 0 #define DB double #define mod 10000 inline int read() { int x=0,f=1; char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') f=-f; ch=getchar(); } while(isdigit(ch)) { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } inline void put(int x) { if(x<0) { x=-x; putchar('-'); } if(x>9) put(x/10); putchar(x%10+'0'); } int f[105][10500]; int n; int k; int ans; signed main() { n=read(); k=read(); for(int i=1;i<=n;i++) f[i][0]=1; for(int i=2;i<=n;i++) { int tot=0; for(int j=0;j<=k;j++) { (tot+=f[i-1][j])%=mod; f[i][j]=tot%mod; if(j-i+1>=0) (((tot-=f[i-1][j-i+1])+=mod)%=mod); } } put(f[n][k]%mod); olinr ~~(0^_^0)+love_nmr; }
----olinr