CF-959(C-E)

CF-959

Problem - C - Codeforces

dp+双指针

分析

要找到满足顺序执行操作后g值大于零的区间数。我们以以i为左端点考虑,对于和小于x的区间[i,j],对答案的贡献就是区间长度j-i,而对于第一个和大于x的区间[i,j],对答案贡献则是以j+1为左端点时的合法区间的数量

操作

对于每个端点i,我们可以预处理出第一个使得区间和大于x的点j,用f[i]表示以i为左端点的合法区间数,,转移方程则是$f[i]=f[p[i]+1]+p[i]-i$,也就得到了,最后对f[i]求和即可

const int N=2e5+5;
int f[N],p[N];
void solve() {
	int n,x;cin>>n>>x;
	vector<int>a(n+2);
	rep(i,1,n) cin>>a[i];
	int ans=0,j=0,now=0; 
	rep(i,1,n){
		while(j<=n&&now<=x){
			now+=a[++j];
		} 
		p[i]=j;
		now-=a[i];
//		cout<<i<<" "<<j<<" "<<now<<endl;
	}
	f[n+1]=0,f[n+2]=0;
	per(i,n,1){
		f[i]=f[p[i]+1]+p[i]-i;
		ans+=f[i];
//		cout<<f[i]<<" \n"[i==1];
	}
	cout<<ans<<endl;
}

Problem - D - Codeforces

抽屉原理

常用于存在性的证明

n个物品放n+1个抽屉一定存在一个抽屉至少有两件物品

也包含有物品相同的情况

对于第x个操作,即以联通x条边,图中已有x+1个点,又所有数$modx$的值一定在[0,x-1]——有x种可能的值,所以x+1个点中一定存在两个点u、v满足$$u\equiv v$$(mod x),也即$x|(u-v)$

因为x是从1开始取的,所以以上的“已有”是成立的

注意只有倒着取x的值才能保证一定有解……

const int N=2e3+5;
int a[N],_,v[N];//,pre[N]
void solve() {
	int n;cin>>n;
	rep(i,1,n) cin>>a[i],v[i]=0;
	vector<pair<int,int>>ans;
	per(i,n-1,1){
//		rep(k,0,i-1) pre[k]=-1;
		vector<int>pre(i,-1);
		rep(j,1,n){
//			if(v[j]) continue;
			if(v[j]==0&&pre[a[j]%i]!=-1){
				ans.push_back({pre[a[j]%i],j});
				v[j]=1;
				break;				
			}
			pre[a[j]%i]=j;
		}
	}
	reverse(ans.begin(),ans.end());
	cout<<"YES\n";
	for(auto [x,y]:ans) cout<<x<<" "<<y<<endl;
}

Problem - E - Codeforces

最大或和

最终要把所有子树都删除,求这个过程中删除的子树大小的最大或和

对于一个大小为n的树,要得到n-1,我们可以先删1个子节点,再删除整个子树,同样,要得到n-2,可以先删两个子节点……也就是说我们可以得到[1,n]的所有值

也就是说只与每个子树的大小n有关……

设x为$[1,该子树的大小]$的任意值,于是问题转化为:求k个x值或和的最大值,显然可以对每个子树的大小拆位处理,对于第i位,如果能找到至少两个1,那么最优解是加上$2{i+1}-1$,否则若是只有一个1,显然保留该位,即加上$2i$最优

这部分可以自己手推一下……

int a[N],_;
void solve() {
	int n,k,x;cin>>k;
	int mx=0;
	rep(i,1,k){
		cin>>a[i];
		rep(j,1,a[i]-1) cin>>x;
	}
	int ans=0;
	per(i,31,0){
		int cnt=0;
		rep(j,1,k){
			if(a[j]>>i&1) cnt++;
		}
//		cout<<i<<" "<<cnt<<endl;
		if(cnt>=2){
			ans+=(1ll<<(i+1))-1;
			break;
		}
		else if(cnt==1) ans+=1ll<<i; 
	}
	cout<<ans<<endl;
}
posted @ 2024-07-20 16:33  mono_4  阅读(19)  评论(0编辑  收藏  举报