• 【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;
    }
    
  • 相关阅读:
    结对第二次作业——某次疫情统计可视化的实现
    结对第一次—疫情统计可视化(原型设计)
    软工实践寒假作业(2/2)
    软工实践寒假作业(1/2)
    个人作业——软件工程实践总结&个人技术博客
    个人技术总结
    个人作业——软件评测
    结对第二次作业——某次疫情统计可视化的实现
    结对第一次—疫情统计可视化(原型设计)
    软工实践寒假作业(1/2)
  • 原文地址:https://www.cnblogs.com/ywwyww/p/10198133.html
Copyright © 2020-2023  润新知