zoukankan      html  css  js  c++  java
  • 【ZJOI2016】线段树

    【ZJOI2016】线段树

    img
    img
    img

    ZJOI的题神啊。

    我们考虑计算每个位置(p),它在操作过后变成第(x)个数的操作序列数。

    我们枚举(x)。我们先得到了(L_x,R_x)表示最左边比(x)小的数以及最右边比(x)小的数(权值相同编号小的更小)。设(f_{i,l,r})表示前(i)个操作结束后,恰好([l,r])的权值(leq a_x)([L_x,l-1],[r+1,R_x])的权值(> a_x)的方案数。初始(f_{0,L_x,R_x}=1)

    考虑转移。我们新的状态(l',r')一定是有(l',t)或者(t,r')转移过来的。

    以第一种为例:

    [displaystyle f_{i,l',r'}=sum_{t=r'+1}^{R_x}f_{i-1,l',t*(n-t)} ]

    然后这个可以前缀和优化。

    还有就是第(i)个操作区间为([1,l-1],[l,r],[r+1,n])的子区间,这样的话(l'=l,r'=r)

    开始想的状态是(f_{i,l,r})表示([l,r])的权值(>a_x)的,怎么都转移不了。

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define N 405
    #define int ll
    using namespace std;
    inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
    
    const ll mod=1e9+7;
    int f[2][N][N];
    int n,q;
    int w[N];
    int L[N],R[N];
    int sum[N];
    int g[N][N];
    
    void solve(int L,int R,int id) {
    	for(int i=L;i<=R;i++)
    		for(int j=i;j<=R;j++)
    			f[0][i][j]=0;
    	f[0][L][R]=1;
    	int now=0;
    	for(int i=0;i<q;i++) {
    		for(int l=L;l<=R;l++) {
    			int tem=0;
    			for(int r=R;r>=l;r--) {
    				(f[now^1][l][r]=tem);
    				(tem+=1ll*f[now][l][r]*(n-r))%=mod;
    			}
    		}
    		for(int r=L;r<=R;r++) {
    			ll tem=0;
    			for(int l=L;l<=r;l++) {
    				(f[now^1][l][r]+=tem)%=mod;
    				(tem+=1ll*f[now][l][r]*(l-1))%=mod;
    			}
    		}
    		for(int l=L;l<=R;l++) {
    			for(int r=l;r<=R;r++) {
    				(f[now^1][l][r]+=1ll*f[now][l][r]*(sum[r-l+1]+sum[l-1]+sum[n-r]))%=mod;
    			}
    		}
    		now^=1;
    	}
    	for(int i=L;i<=R;i++) {
    		int tem=0;
    		for(int j=R;j>=i;j--) {
    			(tem+=f[now][i][j])%=mod;
    			(g[j][id]+=tem)%=mod;
    		}
    	}
    }
    
    bool cmp(int a,int b) {
    	if(w[a]!=w[b]) return w[a]<w[b];
    	return a<b;
    }
    
    int st[N];
    ll ans[N];
    
    main() {
    	n=Get(),q=Get();
    	for(int i=1;i<=n;i++) sum[i]=i*(i+1)/2;
    	for(int i=1;i<=n;i++) w[i]=Get();
    	for(int i=1;i<=n;i++) st[i]=i;
    	sort(st+1,st+1+n,cmp);
    	for(int i=1;i<=n;i++) {
    		L[i]=R[i]=i;
    		for(int j=i-1;j>=1&&w[j]<w[i];j--) L[i]=j;
    		for(int j=i+1;j<=n&&w[j]<=w[i];j++) R[i]=j;
    		solve(L[i],R[i],i);
    	}
    	for(int i=1;i<=n;i++) {
    		ll pre=0;
    		for(int j=1;j<=n;j++) {
    			if(!g[i][st[j]]) continue ;
    			g[i][st[j]]=(g[i][st[j]]-pre+mod)%mod;
    			pre=(pre+g[i][st[j]])%mod;
    			(ans[i]+=1ll*w[st[j]]*g[i][st[j]])%=mod;
    		}
    	}
    	for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
    	return 0;
    }
    
    
  • 相关阅读:
    vue element 表格错位问题
    echarts tooltip 按值的降序显示 tip 信息
    前端 玫瑰花小样式
    echarts X轴数据过多批量显示
    微信js sdk的使用初步理解
    对象 的循环嵌套
    移动端拉起电话请求
    js后加版本号
    数组排序于数组去重
    es6数组的方法
  • 原文地址:https://www.cnblogs.com/hchhch233/p/10553900.html
Copyright © 2011-2022 走看看