zoukankan      html  css  js  c++  java
  • 【AGC030D】Inversion Sum DP

    题目大意

      有一个序列 (a_1,a_2,ldots,a_n),有 (q) 次操作,每次操作给你两个数 (x,y),你可以交换 (a_x,a_y),或者什么都不做。

      问你所有 (2^q) 种情况中逆序对的个数之和。

      (n,qleq 3000)

    题解

      考虑对于每一对 (i,j),计算 (q) 次操作后 (a_i)(a_j) 的大小关系。

      记 (f_{i,j,k}) 为操作 (i) 次后,(a_j,a_k) 这对数中较小的在 (j),较大的在 (k) 的概率。

      每次操作只会修改 (O(n)) 个位置的DP值。

      时间复杂度:(O(n^2+qn))

    题解

    #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
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    E
    D
    Npp ChangeLog
    c++ 书籍(zz)
    再好的工作是为了更好的生活
    如何将JPG格式的图片转换成PNG格式
    点分治
    团体程序设计天梯赛(CCCC) L3021 神坛 的一些错误做法(目前网上的方法没一个是对的) 和 一些想法
    团体程序设计天梯赛(CCCC) L3019 代码排版 方法与编译原理密切相关,只有一个测试点段错误
    团体程序设计天梯赛(CCCC) L3015 球队“食物链” 状态压缩
  • 原文地址:https://www.cnblogs.com/ywwyww/p/10198133.html
Copyright © 2011-2022 走看看