【AGC030D】Inversion Sum DP

題目大意

  有一個序列 \(a_1,a_2,\ldots,a_n\),有 \(q\) 次操做,每次操做給你兩個數 \(x,y\),你能夠交換 \(a_x,a_y\),或者什麼都不作。dom

  問你全部 \(2^q\) 種狀況中逆序對的個數之和。spa

  \(n,q\leq 3000\)code

題解

  考慮對於每一對 \(i,j\),計算 \(q\) 次操做後 \(a_i\)\(a_j\) 的大小關係。get

  記 \(f_{i,j,k}\) 爲操做 \(i\) 次後,\(a_j,a_k\) 這對數中較小的在 \(j\),較大的在 \(k\) 的機率。string

  每次操做只會修改 \(O(n)\) 個位置的DP值。it

  時間複雜度:\(O(n^2+qn)\)io

題解

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<functional>
#include<cmath>
#include<vector>
#include<assert.h>
//using namespace std;
using std::min;
using std::max;
using std::swap;
using std::sort;
using std::reverse;
using std::random_shuffle;
using std::lower_bound;
using std::upper_bound;
using std::unique;
using std::vector;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef std::pair<int,int> pii;
typedef std::pair<ll,ll> pll;
void open(const char *s){
#ifndef ONLINE_JUDGE
    char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
void open2(const char *s){
#ifdef DEBUG
    char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
int rd(){int s=0,c,b=0;while(((c=getchar())<'0'||c>'9')&&c!='-');if(c=='-'){c=getchar();b=1;}do{s=s*10+c-'0';}while((c=getchar())>='0'&&c<='9');return b?-s:s;}
void put(int x){if(!x){putchar('0');return;}static int c[20];int t=0;while(x){c[++t]=x%10;x/=10;}while(t)putchar(c[t--]+'0');}
int upmin(int &a,int b){if(b<a){a=b;return 1;}return 0;}
int upmax(int &a,int b){if(b>a){a=b;return 1;}return 0;}
const int N=3010;
const ll p=1000000007;
ll fp(ll a,ll b)
{
    ll s=1;
    for(;b;b>>=1,a=a*a%p)
        if(b&1)
            s=s*a%p;
    return s;
}
const ll inv2=fp(2,p-2);
int a[N];
int n,q;
ll f[N][N];
int main()
{
    open2("d");
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(a[i]<a[j])
                f[i][j]=1;
    int x,y;
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d",&x,&y);
        f[x][y]=f[y][x]=(f[x][y]+f[y][x])*inv2%p;
        for(int j=1;j<=n;j++)
            if(j!=x&&j!=y)
            {
                f[x][j]=f[y][j]=(f[x][j]+f[y][j])*inv2%p;
                f[j][x]=f[j][y]=(f[j][x]+f[j][y])*inv2%p;
            }
    }
    ll ans=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
            ans=(ans+f[i][j])%p;
    ans=ans*fp(2,q)%p;
    ans=(ans%p+p)%p;
    printf("%lld\n",ans);
    return 0;
}
相關文章
相關標籤/搜索