问题描述
Tom学会了通过写程序求出一个1-n的排列的逆序对数,但他的老师给了他一个难题:
给出一个1-n的排列,求所有字典序比它小的1-n的排列的逆序对数之和。
Tom一时不知道该怎么做,所以他来找你帮他解决这个问题。
因为数可能很大,答案对
109+7
取模。
输入描述
输入包含多组数据(大约20组)。对于每一组数据,第一行一个正整数n,第二行n个数,是一个n的排列。
n≤100
输出描述
对于每组数据输出一行,答案模
109+7
。
输入样例
3 2 1 3 5 2 1 4 3 5
输出样例
1 75
题解:主要就是枚举,bc的题解写的很清楚
总结:
1.如果比赛中有道题目卡在一块了,应该赶紧看看其他题,缓解一下,避免进入死胡同
2.这次因为三重循环的变量写错了WA了好几次,貌似这种情况碰到很多遍了,以后再碰到三重循环的时候,写完简
单检查一遍还是比较有必要的
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
#define MAXN 105
const int MOD = 1e9 + 7;
LL dp[MAXN],d[MAXN],s[MAXN],ans;
int num[MAXN];
int main()
{
dp[0] = 1;
for(int i = 1;i < MAXN;i++)
dp[i] = (dp[i - 1] * i) % MOD;
for(int i = 2;i < MAXN;i++)
d[i] = ((i * d[i - 1]) % MOD + (dp[i - 1] * (i * (i - 1) / 2)) % MOD) % MOD;
int n;
while(scanf("%d",&n) != EOF)
{
for(int i = 0;i < n;i++)
scanf("%d",&num[i]);
for(int i = 1;i < n;i++)
{
s[i] = 0;
for(int j = 1;j < n;j++)
for(int k = 0;k < min(i,j);k++)
if(num[k] > num[j])s[i]++;
}
ans = 0;
for(int i = n - 2;i >= 0;i--)
{
for(int j = i + 1;j < n;j++)
{
LL cur = 0;
if(num[i] > num[j])
{
swap(num[i],num[j]);
for(int k = i;k < n;k++)
{
if(num[i] > num[k])cur++;
}
ans = (ans + (s[i] + cur) * dp[n - i - 1] + d[n - i - 1]) % MOD;
swap(num[i],num[j]);
}
}
}
printf("%I64d\n",ans);
}
}