版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/HuangXinyue1017/article/details/83472545
Time Limits: 2000 ms Memory Limits: 524288 KB
Description
院子落叶,跟我的思念厚厚一叠;窗台蝴蝶,像诗里纷飞的美丽章节……
Input
小 H 是一个喜欢养花的女孩子。
她买了 n 株花,编号为一里香,二里香……七里香……n 里香,她想把这些花分别种在 n个不同的花盆里。
对于一种方案,第 i 个花盆里种的是 ai 里香,小 H 定义其美丽值为:
第一行一个整数 n,第二行有 n 个整数表示 {pi}。pi表示第i个花盆里不可以种ai里香
Output
一个整数,表示答案对 109 + 9 取模的结果。
Sample Input
3
2 1 3
Sample Output
7
Data Constraint
对于 30% 的数据,n ≤ 16。
对于 60% 的数据,n ≤ 100。
对于 100% 的数据,n ≤ 5000,{pi} 是一个排列。
Solution
- 这题嘛,DP啊……菜鸡的我只会写暴力
- 设 表示一共有 个元素,其中 个元素有位置上的限制, 个元素没有位置限制
- 有限制指的假定待放入元素为 ,存在位置 ,而第 个位置还没有填入元素
- 这样我们就有转移式
- ……A
- ……B
- A式就是错排公式,这里的推导过程简单清晰又自然
- B式
然后我们分情况讨论 - 在 上, 在 上,有 种情况,贡献值为
- 上面情况只满足一个,有
种情况,贡献值为
(分别考虑 在 和 在 的情况减去 同时在 的情况) - 两个条件都不满足,有 种情况,贡献值为
- 所以答案为
Code
#include<algorithm>
#include<cstdio>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
#define ll long long
using namespace std;
const int N=5010,P=1e9+9;
int n,p[N];
ll f[N][3];
int main()
{
freopen("derangement.in","r",stdin);
freopen("derangement.out","w",stdout);
scanf("%d",&n);
fo(i,1,n) scanf("%d",&p[i]);
f[0][0]=1,f[1][0]=0,f[0][1]=1,f[0][2]=2;
fo(x,2,n) f[x][0]=(x-1)*(f[x-1][0]+f[x-2][0])%P;
fo(x,1,n)
fo(y,1,2)
f[x][y]=(x*f[x-1][y]%P+y*f[x][y-1]%P)%P;
ll s=0,ans=0;
fo(i,2,n) s=(s+(i*(i-1)/2)%P)%P;
fo(i,1,n)
fo(j,i+1,n)
{
ll a1,a2,a3;
a1=max(0,p[j]-p[i]);
a2=(p[j]*(p[j]-1)/2)%P;
a2=(a2+((1+n-p[i])*(n-p[i])/2)%P)%P;
a2=((a2-2*a1)%P+P)%P;
a3=((s-a1-a2)%P+P)%P;
a3=((a3-(p[i]*(p[i]-1)/2)%P)%P+P)%P;
a3=((a3-((1+n-p[j])*(n-p[j])/2)%P)%P+P)%P;
a3=a3+max(0,p[i]-p[j]);
ans=(ans+(j-i)*(a1*f[n-2][0]%P+a2*f[n-3][1]%P+a3*f[n-4][2]%P)%P)%P;
}
printf("%d",ans);
}