2021-7-8刷题题解

codeforces暑假刷题(1200-1400)

1371B - Magical Calendar

题意:给定n天和r 有一种一周的天数可以为1-r变化的日历 问连续的n天在所有变化的日历上有多少种情况(重复的不算)

思路:当一周有一天时那么就是一个宽为一的长方形,当一周有两天时我们可以选择从第一天开始或者从第二天开始。以此类推。但是当r>=n时那么就只有一种情况就是一整个长方形,应为当选择从大于n的天数开始放的时候会和前面的情况重复。

代码如下:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

int main()
{
	int t;cin>>t;
	while(t--)
	{
		ll x,y;
		cin>>x>>y;
		if(x<=y)
		{
			y=min(x-1,y);
			cout<<y*(y+1)/2+1<<endl; 
		}
		else cout<<y*(y+1)/2<<endl;	
	}
	return 0;	
}

1369B - AccurateLee

题意:给了一个n长度的字符串,每次操作可以将连续的10删去任意一个,问最后通过有限次操作使得字符串最小为多少,在都是最小的情况下长度最小的优先。

思路:当一个子字符串开始为1结尾为0时我们可以发现一个规律无论他们中间是什么都可以被删去只剩下最后一个0,那么我们更具这个结论我们可以去寻找这个字符串最前面的1的位置x和最后面0的位置y。如果x>y那么就是不可以被操作了直接输出原先的的字符串就好了,否则我们直接删去中间的字符串输出两端的字符串。

代码如下:

#include<bits/stdc++.h>

using namespace std;

int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		string s;
		cin>>n>>s;
		int x=-1,y=-1;
		for(int i=0;i<n;i++)
			if(s[i]=='1')
			{
				x=i;
				break;
			}
		for(int i=n-1;i>=0;i--)
			if(s[i]=='0')
			{
				y=i;
				break;
			}
		
		if(x>y||x==-1||y==-1) cout<<s<<endl;
		else
		{
			for(int i=0;i<x;i++) cout<<s[i];
			for(int i=y;i<n;i++) cout<<s[i];
			puts("");	
		}	
	}
	return 0;
}

1352C - K-th Not Divisible by n

题意:求出第k个不可以被n整除的数字

思路:我们将数字分为很多组每组包含一个可以被n整除的 那么第k个就是k/(n-1)+k%(n-1) 如果k%(n-1)==0那么就是k/(n-1)-1

代码如下:

#include<bits/stdc++.h>

using namespace std;

int main()
{
	int t;cin>>t;
	while(t--)
	{
		int n,m;
		cin>>n>>m;
		int k=m/(n-1);
		int l=m%(n-1);
		if(!l) cout<<k*n-1<<endl;
		else cout<<k*n+l<<endl;
	}
	return 0;
}

1326C - Permutation Partitions

题意:将长度n的数组分为k个区间使得每个区间的最大值的总和最大问最多可以有多少种不同的分法

思路:最大的和已经是确定的就是前k个最大的数字的和然后就是分组问题,在这里我们可以用到插板法。算出前k个大的数的位置然后相减相乘。

代码如下:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N=1e6+10;

ll a[N];

int main()
{
	ll n,k;
	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>a[i];
	ll sum=0,p=-1,ans=1;
	for(int i=1;i<=n;i++)
	{
		if(a[i]>=n-k+1) 
		{
			sum+=a[i];
			if(p!=-1)
				ans=ans*(i-p)%998244353;
			p=i;
		}
	}
	cout<<sum<<' '<<ans<<endl;
	return 0;
}

988D - Points and Powers of Two(*1800)

题意:给定一个长度为n的数组,找到最长的使得任意的两个位置的数字的差值的绝对值是2的幂。

思路:有个结论:找出的数组的长度最大为三那么我们就可以枚举每个数从小到大的情况如果有三个直接输出否者判断是否有两个的情况如果两个也没有那么就任意输出一个数

代码如下:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N=1e6+10;

ll a[N];
int n;

int main()
{
	cin>>n;
	map<ll,int> p;
	vector<ll> q; 
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
		p[a[i]]=1;
	}
	
	ll t=1;
	while(t<=2e9)
	{
		q.push_back(t);
		t*=2;
	}
	
	ll x,y;
	bool flag=false;
	for(int j=0;j<n;j++)
	{
		for(ll i=0;i<q.size();i++)
		{
			if(p.find(a[j]+q[i])!=p.end()&&p.find(a[j]+2*q[i])!=p.end())
			{
				cout<<3<<endl;
				ll ans1=a[j]+q[i],ans2=a[j]+2*q[i];
				cout<<a[j]<<' '<<ans1<<' '<<ans2<<endl;
				return 0;	
			}
			else if(p.find(a[j]+q[i])!=p.end()&&!flag)
			{
				flag=true;
				x=a[j];
				y=a[j]+q[i];	
			}		
		}	
	}
	
	if(flag) cout<<2<<endl<<x<<' '<<y<<endl;
	else cout<<1<<endl<<a[0]<<endl;
	
	return 0;
}

1380B - Universal Solution

题意:给定一个字符串长度为n 每次可以从1-n的位置开始 你要创造一个字符串使得赢它的次数最多(石头剪刀布)

思路:我们可以直接找到字符串中出现最多次的那个然后全部输出它的反面就好了。

代码如下:

#include<bits/stdc++.h>

using namespace std;

int main()
{
	int t;cin>>t;
	while(t--)
	{
		string s;
		cin>>s;
		int n=s.size();
		int a=0,b=0,c=0;
		for(int i=0;i<n;i++)
		{
			if(s[i]=='S') a++;
			else if(s[i]=='R') b++;
			else c++;	
		}
		
		if(a>=b&&a>=c)
		{
			for(int i=0;i<n;i++)
				cout<<'R';
			puts("");	
		} 	
		else if(b>=a&&b>=c)
		{
			for(int i=0;i<n;i++)
				cout<<'P';
				puts("");
		}
		else
		{
			for(int i=0;i<n;i++)
				cout<<'S';
			puts("");
		}
	}
	return 0;	
} 

1375B - Neighbor Grid

题意:给定一个二维矩阵,每当出现一个大于零的数字x那么它的周围至少出现x个大于0数字以此类推新增加的数字也会被算在规则之内。你可以操作无限次在某个位置上增加1。如果最后的二位矩阵满足条件那么输出yes和这个矩阵否则输出no

思路:我们可以考虑最极端的情况 (在代码中展示到) 就是每个位置都是最大值,那么去判断原先矩阵如果某个位置比这个最极端的值还要大那么就是no否者直接输出这个最极端的情况。

代码如下:

#include<bits/stdc++.h>

using namespace std;

const int N=1e3+10;

int n,m;
int a[N][N];
 
bool check()
{
	for(int j=1;j<m-1;j++)
		if(a[0][j]>3||a[n-1][j]>3)
			return false;
	
	for(int i=1;i<n-1;i++)
		if(a[i][0]>3||a[i][m-1]>3)
			return false;
	
	for(int i=1;i<n-1;i++)
		for(int j=1;j<m-1;j++)
			if(a[i][j]>4)
				return false;
	return true;
}
int main()
{
	int t;cin>>t;
	while(t--)
	{
		cin>>n>>m;
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++)
				cin>>a[i][j];
		
		if(a[0][0]>2||a[0][m-1]>2||a[n-1][0]>2||a[n-1][m-1]>2||!check())
		{
			cout<<"NO"<<endl;
			continue;	
		}		
		cout<<"YES"<<endl;
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				if(i==1&&(j==1||j==m)) cout<<2<<' ';
				else if(i==1) cout<<3<<' ';
				else if(i>=2&&i<=n-1&&(j==1||j==m)) cout<<3<<' ';
				else if(i>=2&&i<=n-1) cout<<4<<' ';
				else if(i==n&&(j==1||j==m)) cout<<2<<' ';
				else cout<<3<<' ';
			}
			puts("");
		}
	}
	return 0;
}

1375B - Neighbor Grid

题意:给了两个长度为n的数组 a数组是餐厅人员帮你送饭的时间他们是同出发的所以他们一起送的时间就是你要选择的他们中间的最大值 还有b数组就是你自己去拿需要花费的时间这个时间是叠加的。问你怎么样合理安排才能使得花费的世家最少。

思路:我们可以先将两个数组存进pair中然后对第一关键字进行升序排序第二关键字降序排序。同时第二关键字从后改一个后缀和。然后循环一遍取最大值的最小值。

代码如下:

#include<bits/stdc++.h>
#define ll long long

using namespace std;

const int N=2e5+10;

ll s[N];
pair<ll,ll> a[N];

bool cmp(pair<ll,ll>a,pair<ll,ll>b){
    if(a.first!=b.first)return a.first<b.first;
    else return a.second>b.second;
}

int main()
{
	int t;cin>>t;
	while(t--)
	{
		int n;cin>>n;
		for(int i=0;i<n;i++) cin>>a[i].first;
		for(int i=0;i<n;i++) cin>>a[i].second;
		sort(a,a+n,cmp);
		s[n-1]=a[n-1].second;
		for(int i=n-2;i>=0;i--) s[i]=s[i+1]+a[i].second;
		s[n]=-1;
		ll res=0x3f3f3f3f,ans;
		for(int i=0;i<n;i++)
		{
			ans=max(a[i].first,s[i+1]);
			res=min(res,ans);
		}
		res=min(res,s[0]);
		res=min(res,a[n-1].first);
		cout<<res<<endl;
	}
	return 0;
}

1365C - Rotation Matching

题意:给定长度为n的a数组和b数组 b数组可以通过向右移动(会有循环)使得和a数组对应相等的最多,问最多有多少数字相等。

思路:我们可以统计出b数组中每个数字向右移动到a所对应数字的位置的移动步数,相等的最多的就是移动中对应相等最多的数字。

代码如下:

#include<bits/stdc++.h>

using namespace std;

const int N=2e5+10;

int a[N],b[N],c[N];

int main()
{
	map<int,int> p;
	int n,ans=0;cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		c[a[i]]=i;
	}
	for(int i=1;i<=n;i++)
	{
		cin>>b[i];
		int x=i-c[b[i]];
	    if(x<0) x+=n;
		p[x]++;
		ans=max(ans,p[x]);
	}
	cout<<ans<<endl;		
	return 0;
}

1418B - Negative Prefixes

题意:给定一个长度为n的数组和一个01数组 0代表这个位置的数字可以被操作1代表不可以。操作只可以交换位置不能删除或者添加元素。问使得前缀和为负数的情况最小的操作后的数组是什么样的。答案如果有多个任意输出一个。

思路:我们将可以被操作的数字放进一个数组中然后进行排序,为了使得原数组的前缀和尽量都尉正数那么我们在前面要放大的就是降序摆放。

代码如下:

	#include<bits/stdc++.h>
#define ll long long
 
using namespace std;

const int N=2e5+10;

ll a[N],vis[N];
ll b[N],s[N];

int main()
{
	int t;cin>>t;
	while(t--)
	{
		int n,l=0;cin>>n;
		for(int i=0;i<n;i++) cin>>a[i];
		for(int i=0;i<n;i++) cin>>vis[i];
		
		for(int i=0;i<n;i++)
			if(!vis[i])
				b[l++]=a[i];
		
		sort(b,b+l);
		for(int i=0;i<n;i++)
			if(!vis[i])
				a[i]=b[--l];
		
		for(int i=0;i<n;i++)
			cout<<a[i]<<' ';
		puts("");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值