• 6846. 【2020.11.02提高组模拟】旅人1970


    给出一个可重集,(a_i)表示(i)的出现次数。分成若干个集合,最小化每个集合的(2)的最小众数次方之和。

    支持修改。

    (nle 2*10^5,1le a_ile 10^5)

    (qle 10^5)


    题目显然可以转化成:选择不可重集合(S),满足:(sum a_{s_i}ge max a_i),然后使(S)从大往小字典序最小。

    这样就可以得到(O(nq))做法:找到最小的前缀,使得前缀和大于等于(max a_i),然后求出多余的部分,从后往前扫能删就删。

    这里有性质:删的连续段个数为(O(sqrt V))级别,(V)为值域。

    具体证明考虑:对于一个没有删的位置(i),一定有(a_i>sum_{s_j<i}a_{s_j})。把没有删的段提出来,最坏情况下每段只有一个并且取到下界。可以发现不同段的下界是递增的(因为(a_i)为正数),并且没有删的数的和小于(2V)(否则可以再删)。于是连续段个数为(O(sqrt V))

    时间复杂度(O(qsqrt Vlg n))

    题解说卡不满,的确感觉上卡不满,但是为什么我吸氧后才过了?


    #pragma GCC optimize("O2")
    #pragma G++ optimize("O2")
    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <set>
    #define N 200005
    #define ll long long
    #define mo 998244353
    #define min(a,b) ((a)<(b)?(a):(b))
    int input(){
    	char ch=getchar();
    	while (ch<'0' || ch>'9')
    		ch=getchar();
    	int x=0;
    	do{
    		x=x*10+ch-'0';
    		ch=getchar();
    	}
    	while ('0'<=ch && ch<='9');
    	return x;
    }
    int Num,n;
    int pw2[N];
    int a[N];
    multiset<int> s;
    ll sum[N*4];
    int mn[N*4];
    void build(int k,int l,int r){
    	if (l==r){
    		sum[k]=mn[k]=a[l];
    		return;
    	}
    	int mid=l+r>>1;
    	build(k<<1,l,mid);
    	build(k<<1|1,mid+1,r);
    	mn[k]=min(mn[k<<1],mn[k<<1|1]);
    	sum[k]=sum[k<<1]+sum[k<<1|1];
    }
    void change(int k,int l,int r,int x,int c){
    	if (l==r){
    		sum[k]=mn[k]=c;
    		return;
    	}
    	int mid=l+r>>1;
    	if (x<=mid) change(k<<1,l,mid,x,c);
    	else change(k<<1|1,mid+1,r,x,c);
    	mn[k]=min(mn[k<<1],mn[k<<1|1]);
    	sum[k]=sum[k<<1]+sum[k<<1|1];
    }
    pair<int,int> find(int k,int l,int r,int v){
    	if (l==r)
    		return make_pair(l,sum[k]-v);
    	int mid=l+r>>1;
    	if (v<=sum[k<<1]) return find(k<<1,l,mid,v);
    	return find(k<<1|1,mid+1,r,v-sum[k<<1]);
    }
    ll res;
    ll getsum(int l,int r){return pw2[r+1]-pw2[l];}
    void dfs(int k,int l,int r,int en,int &s){
    	if (mn[k]>s) return;
    	if (r<=en && sum[k]<=s){
    		s-=sum[k];
    		res-=getsum(l,r);
    		return;
    	}
    	int mid=l+r>>1;
    	if (mid<en)
    		dfs(k<<1|1,mid+1,r,en,s);
    	dfs(k<<1,l,mid,en,s);
    }
    ll query(){
    	int mx=*s.rbegin();
    	pair<int,int> tmp=find(1,1,n,mx);
    	res=getsum(1,tmp.first);
    	if (tmp.first>1)
    		dfs(1,1,n,tmp.first-1,tmp.second);
    	res=(res%mo+mo)%mo;
    	return res;
    }
    int main(){
    //	freopen("imperishable.in","r",stdin);
    //	freopen("imperishable.out","w",stdout);
    	freopen("in.txt","r",stdin);
    	freopen("out.txt","w",stdout);
    	Num=input(),n=input();
    	pw2[0]=1;
    	for (int i=1;i<=n+1;++i)
    		pw2[i]=pw2[i-1]*2%mo;
    	for (int i=1;i<=n;++i)
    		s.insert(a[i]=input());
    	build(1,1,n);
    	printf("%lld
    ",query());
    	int Q;
    	scanf("%d",&Q);
    	while (Q--){
    		int x=input(),y=input();
    		s.erase(s.find(a[x]));
    		s.insert(y);
    		change(1,1,n,x,a[x]=y);
    		printf("%lld
    ",query());
    	}
    	return 0;
    }
    
  • 相关阅读:
    LeetCode【21】 Merge Two Sorted Lists
    LeetCode【2】Add two numbers
    LeetCode【125】Valid Palindrome
    LeetCode【9】Palindrome Number
    LeetCode【20】Valid Parentheses
    LeetCode【1】Two Sum
    LeetCode【8】string to integer(atoi)
    LeetCode【168】Excel Sheet Column Title
    lambda表达式
    UML类图
  • 原文地址:https://www.cnblogs.com/jz-597/p/13916644.html
Copyright © 2020-2023  润新知