zoukankan      html  css  js  c++  java
  • arc108E

    题目大意

    给出一个排列,定义一个排列是合法的当且仅当标记的数满足单调递增

    每次等概率选择一个未标记过的且标记后序列合法的数标记,求期望的标记个数

    n<=2000

    题解

    时间不够咋写6题啊

    考虑每个数的贡献,枚举数a[x],以(x,a[x])为原点建坐标系,则二四象限的点选了x就必无贡献,选了一三象限的点会把范围往中间缩,范围是一个矩形,并且每次只能选矩形内的点

    这样的好处是不用考虑矩形外面的点,因为被分成的矩形之间是独立的,选了其他矩形中的不会影响到当前的

    写成式子有f[i,j]=a/(a+b)f[i,j]+1/(a+b)(...),化一下变成f[i,j]=1/b(...),所以只用考虑矩形中间的即可

    设f[i,j]表示选到[i,j]且ij已选的答案,转移枚举选择点k,如果k=x就为1,否则为f[i,k]或f[k,j]

    直接写是O(n^4)的,发现x的转移长得差不多,所以把f[i,j]变成所有x的答案,转移是f[i,k]+f[k,j]+1->f[i,j]

    这样是O(n^3),把转移的条件转化成两个二维偏序,树状数组解决

    code

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define add(a,b) a=((a)+(b))%mod
    #define low(x) ((x)&-(x))
    #define mod 1000000007
    #define Mod 1000000005
    #define ll long long
    //#define file
    using namespace std;
    
    int sum[2002][2002],a[2002],n,i,j,k,l;
    ll f[2002][2002],w[2002];
    struct tree{
    	int tr[2002];
    	void change(int t,int s) {while (t<=n+1) add(tr[t],s),t+=low(t);}
    	ll find(int t) {ll ans=0;while (t) add(ans,tr[t]),t-=low(t); return ans;}
    } t1[2002],t2[2002];
    
    int get(int X1,int Y1,int X2,int Y2)
    {
    	int ans=sum[X2][Y2];
    	if (X1) ans-=sum[X1-1][Y2];
    	if (Y1) ans-=sum[X2][Y1-1];
    	if (X1 && Y1) ans+=sum[X1-1][Y1-1];
    	return ans;
    }
    
    int main()
    {
    	#ifdef file
    	freopen("arc108E.in","r",stdin);
    	#endif
    	
    	scanf("%d",&n);
    	fo(i,1,n) scanf("%d",&a[i]);a[n+1]=n+1;
    	w[1]=1;
    	fo(i,2,n+1) w[i]=mod-w[mod%i]*(mod/i)%mod;
    	fo(i,0,n+1) sum[i][a[i]]=1;
    	fo(i,0,n+1) fo(j,1,n+1) sum[i][j]+=sum[i][j-1];
    	fo(i,1,n+1) fo(j,0,n+1) sum[i][j]+=sum[i-1][j];
    	
    	fo(l,3,n+2)
    	{
    		fo(i,0,(n+1)-l+1)
    		{
    			j=i+l-1;
    			if (a[i]<a[j])
    			{
    				f[i][j]=(1ll*(get(i,a[i],j,a[j])-2)+t1[i].find(a[j])+t2[j].find(n-a[i]+1))%mod;
    				f[i][j]=f[i][j]*w[get(i,a[i],j,a[j])-2]%mod;
    				
    				t1[i].change(a[j],f[i][j]);
    				t2[j].change(n-a[i]+1,f[i][j]);
    			}
    		}
    	}
    	printf("%lld
    ",(f[0][n+1]+mod)%mod);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    J2ME开发及JBuilder工具的应用
    Oracle 的入门心得
    Java多线程程序设计初步
    网线制作
    手机死机的原因简析
    SIM简介
    谈谈J2ME的几个重要的功能
    手机应该放哪里 如何把危害的程度降到最低
    彩信的基本原理
    oracle学习笔记
  • 原文地址:https://www.cnblogs.com/gmh77/p/14022625.html
Copyright © 2011-2022 走看看