codeforces 2022.11.14--2022.11.21

1748C Zero-Sum Prefixes
题意:给出n个数,其中为0的数可以改变成任意数
要使: ∑ i = 1 j a i = 0 ( 1 < = j < = n ) \sum_{i=1}^{j} a_i =0 (1<=j<=n) i=1jai=0(1<=j<=n) 求 满足这样的 j 最多有多少个

思路:当 ai 为0时,它对于前 i 位的前缀和无影响,从后往前枚举,记录0和上一个0之间前缀和最多的一个数,此时该位0直接改为此数相反值。枚举完答案还要加上mp[0]

void solve()
{
	int n;
	cin>>n;
	vector<ll> a(n+1),sum(n+1);
	for (int i=1;i<=n;i++)
		cin>>a[i],sum[i]=sum[i-1]+a[i];
	map<ll,int> mp;
	int ans=0; 
	for (int i=n;i>=1;i--)
	{
		mp[sum[i]]++;
		if (!a[i])
		{
			int maxn=0;
			for (auto j:mp)
				maxn=max(maxn,j.second);
			ans+=maxn;
			mp.clear();
		}
	}
	cout<<ans+mp[0]<<"\n";
}

1748D ConstructOR
题意:给出a,b,d,求x使得:
a|x,b|x都能被d整除

思路:
以二进制来枚举d的倍数,使得a|x与b|x都等于此倍数
找a,b,d二进制出现1的最低位为minn,如果minn由a或b产生,则无解(无法找到d的倍数在minn位为1)
对于a,b二进制第i位上有1,则x就需加上d<<(i-minn)

void solve()
{
	int minn;
	ll a,b,d;
	cin>>a>>b>>d;
	a=(a|b);
	for (int i=0;;i++)
	{
		if (((a>>i)&1)&&((d>>i)&1)==0)
		{
			cout<<"-1\n";
			return;
		}
		if ((d>>i)&1)
		{
			minn=i;
			break;
		}
	}
	ll ans=d;
	for (int i=0;i<=60;i++)
	{
		if (((a>>i)&1)&&((ans>>i)&1)==0)
			ans+=(d<<(i-minn));
	}
	cout<<ans<<"\n";
}

1747C Swap Game
题意:a和b玩游戏,给出n个数,当轮到某一个人:

  1. a1-=1;
  2. 选择ai和a1交换

当轮到某个人时 a1=0则输

思路:
当某轮存在a1 …0… 则先手必赢–>存在a1=1… 则先手必输
n个数中只有最小的两个数有用,双方都想让对方的a1尽可能的小
于是出现以下策略:
到自己时,选择的i一定是2~n中最小的ai,值为minn
所以当a0>=minn,先手必赢;a0<minn,先手必输

1746C Permutation Operations
题意:给n个数,执行n次操作,第i次操作选择j,使ak+=i(j<=k<=n)
找出某种方案使得该数组中逆序数最少

思路:对于每次操作,选择j,只会改变aj-1与aj的差值,于是求出差分数组,对其中的负数,每次加给最大的负数

struct node
{
	int pos,val;
};
bool cmp(node x,node y)
{
	return x.val>y.val;
}
void solve()
{
	int n;
	cin>>n;
	vector<int> a(100005);
	vector<node> b;
	for (int i=1;i<=n;i++)
	{
		cin>>a[i];
		if (a[i]-a[i-1]<0)
			b.push_back({i,a[i]-a[i-1]});	 
	}
	sort(b.begin(),b.end(),cmp);
	int i=1;
	for (int j=0;j<b.size();j++)
	{
		while (b[j].val<0&&i<=n)
		{
			b[j].val+=i;
			i++;
			cout<<b[j].pos<<" ";
		}
		if (i==n+1)
			break;
	}
	while (i++<=n)
		cout<<n<<" ";
	cout<<"\n";
}

1742G Orray
题意:给出n个数ai,bi=a1|a2…|ai,对a排序,使得b字典序最大

思路:b1=a1,所以第一个数必定ai中最大的数。之后枚举到i时,只需找到bi-1的最高位0,枚举a中未使用且这一位为1的数(预处理存入数组),并找到其中对bi贡献最大的数(使bi-bi-1最大)

void solve()
{
	int n,pos,maxn=0;
	cin>>n;
	vector<bool> sym(n+1);//标记是否使用过
	vector<int> a(n+1);
	vector<vector<int>> good(32);//第i位为1的数
	for (int i=1;i<=n;i++)
	{
		cin>>a[i];
		int temp=a[i];
		for (int j=0;temp;j++)
		{
			if (temp%2==1)
				good[j].push_back(i);//预处理
			temp/=2;
		}
		if (maxn<a[i])
		{
			pos=i;
			maxn=a[i];
		}
	}
	sym[pos]=1;
	cout<<maxn<<" "; //输出b[1]
	for (int i=30;i>=0;i--)
	{
		if (((maxn>>i)&1)==0)//最高位0
		{
			int val=0;
			for (auto j:good[i])//枚举第i位为1的数
			{
				if (sym[j])continue;//已使用的跳过
				if (val<(maxn|a[j])-maxn)
				{
					val=(maxn|a[j])-maxn;
					pos=j;
				}
			}
			if (sym[pos])continue;
			maxn|=a[pos];
			sym[pos]=1;
			cout<<a[pos]<<" ";
		}
	}
	for (int i=1;i<=n;i++)//后续答案已不会改变,输出未选的
	{
		if (!sym[i])
			cout<<a[i]<<" ";
	}
	cout<<"\n";
}

1742F Smaller
题意:给两个字符串s=“a”,t=“a”,每次操作:
1 k x,给s加上k个x
2 k x,给t加上k个y
每次操作完可排序,若存在 s < t,输出YES;反之NO

思路:
贪心+模拟,每次统计s,t中26个字母的个数,s从a开始找最小字母,t从z开始找最大字母。
YES: a的最小字母 < b的最大字母;
NO: a的最小字母 > b的最大字母

l,r继续移动:
a的最小与b的最大为同一字母

特例:
a的最小与b的最大为同一字母 a只有该字母或b只有该字母(具体见代码)

void solve()
{
	int q;
	cin>>q;
	vector<ll> sum1(30),sum2(30);
	sum1[0]++;
	sum2[0]++;
	while (q--)
	{
		ll minn=1e18;
		for (int i=0;i<=25;i++)
			minn=min(minn,min(sum1[i],sum2[i]));
		for (int i=0;i<=25;i++)
			sum1[i]-=minn,sum2[i]-=minn;
		int d,k;
		string x;
		cin>>d>>k>>x;
		int len=x.length();
		if (d==1)
		{
			for (int i=0;i<len;i++)
				sum1[x[i]-'a']+=k;
		}
		else
		{
			for (int i=0;i<len;i++)
				sum2[x[i]-'a']+=k;
		}
		for (int l=0,r=25;l<=26&&r>=-1;)
		{
			while (!sum1[l]&&l<=25){l++;}
			while (!sum2[r]&&r>=0){r--;}
			if (r==-1||(r==-1&&l==26))
			{
				cout<<"NO\n";
				break;
			}
			if (l==26)
			{
				cout<<"YES\n";
				break;
			}
			if (l<r)
			{
				cout<<"YES\n";
				break;
			}
			if (l>r)
			{
				cout<<"NO\n";
				break;
			}
			if (l==r)
			{
				if (sum1[l]==sum2[r])
					l++,r--;
				else if (sum1[l]>sum2[r])
					r--;
				else
					l++;
			}
		}
	}
}

1742D Coprime
题意:给n个数,找i,j使ai与aj互质,求max(i+j),若不存在i,j,输出-1

思路:由数据范围可知,当数据很大时,数组中有很多重复的数,于是可以把每个数的最大位置存下来,之后1000*1000枚举即可

1742E Scuza
题意:给n个数,q次询问,每次询问给一个x,只要ai<=x,i++,问给出的x可以到达最大的i的前缀和为多少

思路:直接求出到达i最小需要的值,之后二分查找upper_bound第一个大于x的位置,输出前缀和即可

1753B Factorial Divisibility
题意:给出n个数ai和一个x,判断是否
∑ 1 n a i m o d x = = 0 \sum_{1}^{n} a_i mod x==0 1naimodx==0

思路:考虑每一个 a i ! a_{i}! ai!,当 a i > = x a_{i}>=x ai>=x时,一定能被 x ! x! x!整除;
对于 a i < x a_{i}<x ai<x,我们只需将多个 a i ! a_{i}! ai!合并为 ( a i + 1 ) ! (a_{i}+1)! (ai+1)!,一直合并到最大,若此时还存在 a i < x a_{i}<x ai<x,则为NO,反之为YES

void solve()
{
	int n,x;
	cin>>n>>x;
	vector<int> sum(500005);
	for (int i=1;i<=n;i++)
	{
		int a;
		cin>>a;
		if (a<=x-1)sum[a]++;
	}
	for (int i=1;i<=x-1;i++)
	{
		if (sum[i]>=i+1)
		{
			sum[i+1]+=sum[i]/(i+1);
			sum[i]-=sum[i]/(i+1)*(i+1);
		}
		if (sum[i])
		{
			cout<<"No";
			return;
		}
	}
	cout<<"Yes";
}

1738B Prefix Sum Addicts
题意:给定一个n,k,给定k个数 a i a_{i} ai 表示为前n-k+i个数的前缀和,问是否能构造出满足前缀和的非降序原数组

思路:先看n-k+1这个数的前缀和,求出最小的 a n − k + 1 a_{n-k+1} ank+1,然后看是否满足 a n − k + 1 < = a n − k + 2 a_{n-k+1}<=a_{n-k+2} ank+1<=ank+2,不满足输出NO
求出后k-1个原数组,判断是否单调递增

1732D1 Balance (Easy version)
题意:给定一个集合{0},进行q次操作
+ x,在集合中加入x
? x,找到一个不存在集合中且能被x整除的最小数

思路:
直接用map mp1标记集合中有哪些数,并用map mp2储存某个数满足题目的最小数(优化时间,减少查询,因为集合中的数变多,最小数要么不变要么变大)

map <ll,ll> mp1,mp2;
void solve()
{
	char ch;
	ll x;
	cin>>ch>>x;
	if (ch=='+')
		mp1[x]=1;
	if (ch=='?')
	{
		while (mp1[mp2[x]+x]==1)
		{
			mp2[x]+=x;
		}
		cout<<mp2[x]+x<<"\n";
	}	
}

1730B Meeting on the Line
题意:在一坐标轴上给出n个人的位置 x i x_{i} xi,每个人有一个穿衣服的时间 t i t_{i} ti,求某一个点使得所有人到该点的时间最小化,误差允许在1e-6以内

思路一:二分答案,找最小的时间,check满足时更新ans(控制精度防T)

const int N=2e5+5;
struct node
{
	int x,dtime;
}a[N];
double ans;
int n;
bool check(double x)
{
	double l=0,r=1e9; 
	for (int i=1;i<=n;i++)
	{
		l=max(l,a[i].x-x+a[i].dtime);
		r=min(r,a[i].x+x-a[i].dtime);
		if (l>r)
			return 0;
	}
	ans=l;
	return 1;
}
void solve()
{
	memset(a,0,sizeof(a));
	double l=0,r=1e9;
	cin>>n;
	for (int i=1;i<=n;i++)
		cin>>a[i].x;
	for (int i=1;i<=n;i++)
		cin>>a[i].dtime;
	while (r-l>0.0000001)
	{
		double mid=(l+r)/2;
		if (check(mid))
			r=mid;
		else
			l=mid;
	}
	cout<<fixed<<setprecision(6)<<ans<<"\n";
}

思路二:待补

1728C Digital Logarithm
题意:给出两个数组,求最少花多少次操作使得两数组相同。
对一个数操作,返回该数的长度

思路:相同的数全部排除,统计a,b中各数的个数,在a中+,在b中-(抵消相同的数)
从最大的数向最小的数枚举,最大的数必须转换成小的(如果a,b中一直没有相同的最终转化为1),对答案产生贡献

void solve()
{
	int n;
	cin>>n;
	map<int,int,greater<int>> sum;
	for (int i=1;i<=2*n;i++)
	{
		int x;
		cin>>x;
		if (i<n+1)	sum[x]++;
		else	sum[x]--;
	}
	int ans=0;
	for (auto i:sum)
	{
		int temp=i.first,cnt=0;
		while (temp)
		{
			temp/=10;
			cnt++;
		}
		sum[cnt]+=sum[i.first];
		ans+=abs(i.second);
	}
	cout<<ans<<"\n";
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您提供的链接是Codeforces的一个问题,问题编号为104377。Codeforces是一个知名的在线编程竞赛平台,经常举办各种编程比赛和训练。Gym是Codeforces的一个扩展包,用于组织私人比赛和训练。您提供的链接指向了一个问题的页面,但具体的问题内容和描述无法通过链接获取。如果您有具体的问题或需要了解关于Codeforces Gym的更多信息,请提供更详细的信息。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [http://codeforces.com/gym/100623/attachments E题](https://blog.csdn.net/weixin_30820077/article/details/99723867)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [http://codeforces.com/gym/100623/attachments H题](https://blog.csdn.net/weixin_38166726/article/details/99723856)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [CodeforcesPP:Codeforces扩展包](https://download.csdn.net/download/weixin_42101164/18409501)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值