Codeforces Round #717 (Div. 2)(ABCD)

A. Tit for Tat

从前往后枚举,把前面的数减到0,然后给最后一个数加上去。操作次数没了就停止

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
long long sum=1;
bool vis[N];
int a[N];
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n,k,g=0;
		cin>>n>>k;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
			int now=a[i];
			a[i]=max(0,a[i]-k);
			k-=now-a[i];
			g+=now-a[i];
		}
		for(int i=1;i<n;i++)printf("%d ",a[i]);
		cout<<a[n]+g;
		cout<<endl;
	}
	return 0;
}

B. AGAGA XOOORRR

用前缀异或。
比如异或出来的前缀数组是
a数组 1 4 5 7 0 4 3 4 0 9 8
下标:1 2 3 4 5 6 7 8 9 10 11
可以发现在0前面的任何一个数x,都可以让0前面变成两段。两段各自的异或就可以是x。比如1-3区间异或为a[3]=5。4-5的异或为a[5]^a[3]=5。则这两段异或值相同
记录最后一个0的位置,如果0在最后。则区间划分成两段。
否则划分成3段。记录0前面有没有数等于0后面的异或值即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
long long sum=1;
int a[N];
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n;
		bool f=0;
		int q=0;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
			a[i]^=a[i-1];
			if(a[i]==0)q=i;
		}	
		int sum=a[n];
		for(int i=1;i<q;i++)if(a[i]==sum)f=1;
		if(f||q==n)puts("YES");
		else puts("NO");
	}
	return 0;
}

C. Baby Ehab Partitions Again

f [ i ] [ j ] f[i][j] f[i][j]表示前i个物品取体积不超过j的最大价值。这里把价值当作体积。
某个子序列的和是x 则 f [ n ] [ x ] = = x f[n][x]==x f[n][x]==x,否则说明取不到和是x的子序列
如果有两个子序列和一样,那么这个和加起来一定是偶数。
如果是奇数,直接输出0
否则 令当前所有物品体积和为s。看是否有和是s/2,如果没有则输出0。否则一定会删除1个数。遍历一遍每个数,如果是奇数直接输出。因为偶数-奇数=奇数,一定不会有两个一样的和加起来是偶数。或者不存在(s-a[i])/2的和也直接输出

#include<bits/stdc++.h>
using namespace std;
const int N=105;
int f[N][N*2000+10],a[N];
int main()
{
	int n;
	cin>>n;
	int m=n*2000,s=0;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		s+=a[i];
		for(int j=a[i];j<=m;j++)
		{
			f[i][j]=max(f[i-1][j],f[i-1][j-a[i]]+a[i]);
		}
	}
	if(s&1)cout<<0;
	else
	{
		if(f[n][s/2]!=s/2)
		{
			cout<<0;
			return 0;
		}
		cout<<1<<endl;
		for(int i=1;i<=n;i++)
		{
			if(a[i]&1||(f[n][(s-a[i])/2]!=(s-a[i])/2))
			{
				cout<<i;
				return 0;
			}
		}
	}
	return 0;
}

D Cut

首先要使分割的每一段里面的数两两都是互质的。
比如有两个数质因数分解分别为 a = 2 3 ∗ 3 4 ∗ 5 2 a=2^3*3^4*5^2 a=233452 b = 2 1 ∗ 3 5 b=2^1*3^5 b=2135
则他们的乘积就是 2 4 ∗ 3 9 ∗ 5 2 2^4*3^9*5^2 243952 lcm为 2 3 ∗ 3 4 ∗ 5 2 2^3*3^4*5^2 233452
要使乘积等于lcm,则每个质因子只能a有或者只能b有。

1.考虑 n e [ i ] ne[i] ne[i]:位置i左边最近的非互质的数的位置
a: 2 3 10 7 5 14
ne :0 0 1 0 3 4
有了ne[i]我们已经可以计算答案了,假如i位置跳到ne[i],我们自然会想把ne[i]+1~i划分为一组。但如果这里面还有两个数是非互质的呢
比如 14 10 5 7 ne[4]=1 ne[3]=2显然我们只能把5和7这两个数组划分为一组。
所以ne[i]=max(ne[i],ne[i-1])即可
2.计算 ne[i] ,从前往后对每个数质因数分解,当前枚举到位置 i ,对a[i]所有的质因子j 。 n e [ i ] = m a x ( n e [ i ] , w e i [ j ] ) ne[i]=max(ne[i],wei[j]) ne[i]=max(ne[i],wei[j])。。。 w e i [ j ] wei[j] wei[j]表示j这个数的位置。然后更新记录这质因子的位置为 w e i [ j ] = i ; wei[j]=i; wei[j]=i;
3.用倍增法快速跳跃。一步步跳可能会超时。倍增法枚举log次即可。
f [ i ] [ j ] f[i][j] f[i][j]表示从 j 这个位置跳 2 i 2^i 2i步到的位置。
f [ i ] [ j ] = f [ i − 1 ] [ f [ i − 1 ] [ j ] ] ; f[i][j]=f[i-1][f[i-1][j]]; f[i][j]=f[i1][f[i1][j]];
即先跳一半再跳一半嘛。
4.计算答案。i从20开始枚举因为 2 20 2^{20} 220> 1 e 5 1e^5 1e5,即从跳 2 i 2^i 2i步开始枚举,从r往l跳,只要跳到范围没有超过l(<l)就跳过去。然后答案加上 2 i 2^i 2i,最终答案还要加上1,要多跳一下。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int ne[N],a[N],wei[N],f[20][N];//wei表示i这个数的位置
int main()
{
	int n,q;
	cin>>n>>q;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	for(int i=1;i<=n;i++)
	{
		int x=a[i];
		for(int j=2;j*j<=x;j++)
		{
			if(x%j==0)
			{
				ne[i]=max(ne[i],wei[j]);
				wei[j]=i;
				while(x%j==0)
				{
					x/=j;
				}
			}
		}
		if(x>1)
		{
			ne[i]=max(ne[i],wei[x]);
			wei[x]=i;
		}
		ne[i]=max(ne[i],ne[i-1]);
		f[0][i]=ne[i];
	}
	for(int i=1;i<=19;i++)
	{
		for(int j=1;j<=n;j++)f[i][j]=f[i-1][f[i-1][j]];
	}
	while(q--)
	{
		int l,r,x,ans=0;
		cin>>l>>r;
		x=r;
		for(int i=19;i>=0;i--)
		{
			if(f[i][x]>=l)
			{
				ans+=1<<i;
				x=f[i][x];
			}
		}
		printf("%d\n",ans+1);
	}
	return 0;
}
/*
5 3
2 14 10 5 7
1 5
*/

有不懂的欢迎评论出来一起探讨!

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值