cf1832

cf1832

A. New Palindrome

题目链接

看回文字符串经过重排是不是还能组成回文字符串。如果字符串不计只出现一次的字符,其余有多个字符都出现偶数次,那么就重排可以组成新的回文字符串。

// Problem: A. New Palindrome
// Contest: Codeforces - Educational Codeforces Round 148 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1832/problem/A
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
#include<stack>
#include<vector>
#include<map>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long LL;
string s;
int cnt[26];
int res;
int T;
int main(){
	cin>>T;
	while(T--){
		cin>>s;
		memset(cnt,0,sizeof(cnt));
		res=0;
		for(int i=0,n=s.length();i<n;i++){
			cnt[s[i]-'a']++;
		}
		for(int i=0;i<26;i++){
			if(cnt[i]>=2) res++;
		}
		if(res>1) puts("YES");
		else puts("NO");
	}

	return 0;
}

B. Maximum Sum

题目链接
每次在k次操作中,每次操作删掉最小的两个数或者最大的一个数。求最后剩下的数的和最大的情况。
直觉上贪心是最小两个数和与最大一个数谁小删除谁,但是这样链样例都过不去。因为每次删除的贡献并不相等。这样的情况遍历才能考虑周全
排完序用前缀和遍历一下就可以考虑所有情况了。
核心公式:res=max(res,sum[n-(k-i)])-sum[i<<1]
n-(k-j)是删除掉几个最大数的前缀和,此时减去i<<1是删除掉几个最小数的前缀和。剩下的就是这种删除策略执行后的值。

// Problem: B. Maximum Sum
// Contest: Codeforces - Educational Codeforces Round 148 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1832/problem/B
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
#include<stack>
#include<vector>
#include<map>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long LL;
typedef pair<LL,int> PLI;
const int N=2e5+10;
int T;
int n,k;
LL a[N];
LL sum[N];
void output(){
	for(int i=1;i<=n;i++){
		cout<<sum[i]<<" ";
	}
	cout<<endl;
}
int main(){
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&k);
		for(int i=1;i<=n;i++)
		{
			scanf("%lld",&a[i]);
		}
		sort(a+1,a+n+1);
		for(int i=1;i<=n;i++)
		{
			sum[i]=sum[i-1]+a[i];
		}
		// output();
		LL res=0;
		for(int i=0;i<=k;i++)
		{
			res=max(res,sum[n-(k-i)]-sum[i<<1]);
		}
		printf("%lld\n",res);
	}

	return 0;
}

C. Contrast Value

题目链接
给定一个数组定义一个条件:\(\vert a_1-a_2\vert+\vert a_2-a_3\vert+\cdots +\vert a_{n-1} -a_n\vert\).
要求给出一个非空子数组其条件\(\vert b_1-b_2\vert+\vert b_2-b_3\vert+\cdots +\vert b_{n-1} -b_n\vert\)不变.
求符合条件的子数组最小长度

考虑条件若去掉绝对值符号,则上述求和公式变为\(b_1-b_n\),但是去掉绝对值的条件是相邻的绝对值内符号相等,那么把所有相邻的绝对值符号内式子符号相等的情况合并即可,合并后剩下式子加1即为最小规模

// Problem: C. Contrast Value
// Contest: Codeforces - Educational Codeforces Round 148 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1832/problem/C
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
#include<stack>
#include<vector>
#include<map>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long LL;
const int N=3e5+10;
int T,n;
int a[N];
void output(vector<int> q){
	for(int i=0,si=q.size();i<si;i++){
		cout<<q[i]<<" ";
	}
	cout<<endl;
}
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		vector<int> q;
		for(int i=0;i<n;i++){
			scanf("%d",&a[i]);
		}
		q.push_back(a[0]);
		for(int i=1;i<n;i++){
			if(q[q.size()-1]!=a[i]) q.push_back(a[i]);
		}
		// output(q);
		int res=1;
		if(q.size()<=1){
			printf("%d\n",res);
		}else{
			int fla= q[0]-q[1]>0?1:0;
			for(int i=1,siz=q.size();i<siz-1;i++){
				int t=q[i]-q[i+1]>0?1:0;
				if(t!=fla){
					fla=t;
					res++;
				}
			}
			printf("%d\n",res+1);
		}
		
	}

	return 0;
}

D1. Red-Blue Operations (Easy Version)

题目链接

给定一个长度为n的序列初始时均为红色。
给定k个操作中的第i个来说:

  • 对于红色的数那么就变为蓝色,同时该数加上i
  • 对于蓝色的数那么就变为红色,同时该数减去i

求最小数最大时最小数的大小

可以证明,要保证最优,必须最小的加最大可加的数,依次类推。

对于操作数k,有以下几种情况:

  1. k<=n,那么每个数都可以增加,按照最优策略加对应的数取最小即可。
  2. k>n,必定存在某些数发生减法操作,但是可以发现最后减法操作就是将若干个-1均分到数列中,那么最后的策略就还是先考虑数先增加再考虑提取数减小。
  3. 考虑当数列第一次全为蓝色时,若还剩余操作数m,考虑减法操作。此时先求出所有的数大于最小数的diff,若大于\(\lfloor m \rfloor\) 则最小数不变,但是当小于时最小数此时减去\(\lceil k/n \rceil\)即可。
// Problem: D1. Red-Blue Operations (Easy Version)
// Contest: Codeforces - Educational Codeforces Round 148 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1832/problem/D1
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define x first
#define y second
typedef pair<int, int> PII;
typedef long long LL;
const int N=1e3+10;
int n,q;
int a[N],backup[N];
void output()
{
	for(int i=1;i<=n;i++)
	{
		cout<<a[i]<<" ";
	}
	cout<<endl;
}
int main()
{
	cin>>n>>q;
	for(int i=1;i<=n;i++)
	{
		cin>>backup[i];
	}
	sort(backup+1,backup+1+n);
	while(q--)
	{
		int k;
		cin>>k;
		for(int i=1;i<=n;i++)
		{
			a[i]=backup[i];
		}
		for(int i=1;i<=n;i++)
		{
			if(!k) break;
			if(k%2==0&&i==n) break;
			a[i]+=k--;
		}
		// output();
		k/=2;
		sort(a+1,a+1+n);
		LL diff=0;
		for(int i=1;i<=n;i++)
		{
			diff+=a[i]-a[1];
		}
		int res=a[1];
		if(k>diff)
		{
			k-=diff;
			res-=(k+n-1)/n;
		}
		cout<<res<<' ';
	}
	
	return 0;
}

D2. Red-Blue Operations (Hard Version)

题目链接

和D1的唯一区别是操作数和数列长度增大,此时上述未优化代码会超时。
此时考虑每个数都会加上\(k-i\) i为该数的位置,而且只需要知道最小的即可,那么可以先预处理数组pre[i]=min(pre[i-1],a[i]-i)。
对于可以大于最小数的总数可以维护所有数的总和来求得。总的来说逻辑不变。
具体优化见代码。

// Problem: D2. Red-Blue Operations (Hard Version)
// Contest: Codeforces - Educational Codeforces Round 148 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1832/problem/D2
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define x first
#define y second
typedef pair<int, int> PII;
typedef long long LL;
const int N=2e5+10;
int n,q,k;
LL s,ps;
LL a[N],pre[N];
int main()
{
	cin>>n>>q;
	s-=(n-1)*(n-2)/2;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
		s+=a[i];
	}
	sort(a,a+n);
	pre[0]=a[0];
	for(int i=1;i<n;i++)
	{
		pre[i]=min(pre[i-1],a[i]-i);//预处理前缀,pre[i]是第i位前最小的a[i]-i
	}
	ps=s;//存总和备份防止篡改
	while(q--)
	{
		s=ps;
		LL ans=0x3f3f3f3f;
		cin>>k;
		if(k<n)
		{
			ans=min(pre[k-1]+k,a[k]);//当数组长度大于操作数时,前面发生加操作的最小数,和未发生加操作的最小数取min即可
		}else if(n==1)//n==1特判
		{
			ans=a[0]-k/2;
			if(k%2)
			{
				ans+=k;
			}
		}else
		{
			//此时没有第一时间对最后一个数操作
			s+=(LL)k*(n-1);//总和加上(n-1)个k
			ans=pre[n-2]+k;//此时以发生加操作的数一定是pre[n-2]+k
			k-=n-1;
			if(k%2)//剩余操作数奇数,那么最后一个数会发生加操作
			{
				s+=k;
				ans=min(ans,a[n-1]+k);
				k--;
			}else//偶数则将多个-1分摊
			{
				ans=min(ans,a[n-1]);
			}
			s-=ans*n;//可以在保持最小值不变情况下的可以减的数
			k/=2;
			if(k>s)
			{
				ans-=(k-s-1)/n+1;
			}
		}
		cout<<ans<<" ";
	}

	return 0;
}

E. Combinatorics Problem

题目链接

注意k<=5这个条件,可以找规律找出解法。
以样例为例,n=5,\(a_1=8\),x=2,y=3,m=100,k=2

\(b_1=0\)
\(b_2=a_1\) \(d_2=a_1\) \(e_2=a_1\)
\(b_3=3a_1+a_2\) \(d_3=2a_1+a_2\) \(e_3=a_1+a_2\)
\(b_4=6a_1+3a_2+a_3\) \(d_4=3a_1+2a_2+a_3\) \(e_4=2a_1+a_2+a_3\)
\(b_5=10a_1+6a_2+3a_3+a_4\) \(d_5=b_5-b_4=4a_1+3a_2+2a_3+a_4\) \(e_5=d_5-d_4=a_1+a_2+a_3+a_4\)

多写几个就可以发现核心是多次进行前缀和的操作,具体次数是k+1次
那么可以进行k+1次前缀和操作即可。

// Problem: E. Combinatorics Problem
// Contest: Codeforces - Educational Codeforces Round 148 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1832/problem/E
// Memory Limit: 1024 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define x first
#define y second
typedef pair<int, int> PII;
typedef long long LL;
const int mod=998244353;
int n,x,y,m,k;
void output(vector<int> a)
{
	for(int i=0,len=a.size();i<len;i++)
	{
		cout<<a[i]<<" ";
	}
	cout<<endl;
}
int main()
{	
	cin>>n;
	vector<int> a(n);
	cin>>a[0]>>x>>y>>m>>k;
	for(int i=1;i<n;i++)
	{
		a[i]=(1ll*a[i-1]*x+y)%m;
	}
	for(int i=0;i<=k;i++)
	{
		for(int j=1;j<n;j++)
		{
			a[j]=(a[j]+a[j-1])%mod;
		}
		// output(a);
	}
	LL res=0;
	for(int i=k-1;i<n;i++)
	{
		res^=1ll*(i+1)*a[i-k+1];
	}
	cout<<res<<endl;
	

	return 0;
}
posted @ 2023-05-14 14:35  viewoverlook  阅读(31)  评论(0编辑  收藏  举报