返回顶部

Codeforces Round #729 (Div. 2) D. Priority Queue (思维,递推)

  • 题意:给你一个序列A,每个元素为\(+ \ x\)或者\(-\),假设\(S\)\(A\)的一个子序列,那么便利\(S\),\(+\ x\)表示贡献加上\(x\),\(-\)表示贡献减去\(S\)中最小的\(x\),并且在序列中删去这个\(x\),问所有子序列的和为多少(\(\mod 998244353\).

  • 题解:先假设一个子序列集合\(S\)中,最后的贡献有\(x\)这个数的贡献,也就是说我们这个\(+\ x\)一定存活到了最后,没有被减去,那么这个集合中,在\(x\)位置之前的且比\(x\)大的数是一定不会受到任何影响的,在\(x\)位置后且不小于\(x\)的数也一定是不会受到任何影响的,我们记这些数的数量为\(cnt\),那么他们的方案数就是\(2^{cnt}\).

    然后我们再对剩下的数进行讨论,可以直接进行遍历,过滤掉上述情况的数,设\(dp[i]\)为最后剩下\(i\)个数的方案数.注意这里是不包含当前所选的这个\(x\)的.再特别注意,在\(i\)遍历到当前位置之前,如果出现\(-\),那么\(dp[0]*=2\),而过了当前位置之后,因为\(x\)是一定要选的,所以就不能再乘2了.剩下的就是一个线性的递推转移即可.

  • 代码:

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 998244353;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
    
    int n;
    char op[N];
    ll a[N];
    ll dp[N]; //除去无影响的数后,剩下i个数的方案数
    ll pw[N];
    
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    	cin>>n;
    	pw[0]=1;
    	for(int i=1;i<=n;++i){
    		cin>>op[i];
    		if(op[i]=='+'){
    			cin>>a[i];
    		}
    		pw[i]=pw[i-1]*2%mod;
    	}
    	ll ans=0;
    	for(int k=1;k<=n;++k){ //全程不包含a[k]的情况
    		if(op[k]!='+') continue;
    		ll cnt=0;
    		for(int i=0;i<=n+5;++i) dp[i]=0;
    		dp[0]=1;
    		for(int i=1;i<=n;++i){
    			if(i<=k && a[i]>a[k]) cnt++;
    			else if(i>k && a[i]>=a[k]) cnt++;
    		}
    		for(int i=1;i<=n;++i){
    			if((i<k && a[i]>a[k]) || (i>k && a[i]>=a[k]) || i==k) continue;
    			if(op[i]=='-'){
    				if(i<k) dp[0]=(dp[0]*2)%mod;  //因为a[k]是必须要选的
    				for(int j=0;j<n;++j) dp[j]=(dp[j]+dp[j+1])%mod;
    			}
    			else{
    				for(int j=n-1;j>=1;--j){
    					dp[j]=(dp[j]+dp[j-1])%mod;
    				}
    			}
    		}
    		for(int i=0;i<n;++i){
    			ans=(ans+pw[cnt]*dp[i]%mod*a[k])%mod;
    		}
    	}
    	cout<<ans<<'\n';
        return 0;
    }
    
    
posted @ 2021-07-08 13:33  Rayotaku  阅读(107)  评论(0编辑  收藏  举报