DIV3 D题后,DIV2 C题后

C. Choose the Different Ones!

Problem - C - Codeforces

给定一个由 n 个整数组成的数组 a,一个由 m 个整数组成的数组 b 和一个偶数 k 。

你的任务是从这两个数组中精确选择 k/2 个元素,使所选择的元素中包含从 1 到 k 的每个整数。

开三个map,第一个存A数组中1<=a[i]<=k的数,第二个存B数组1<=b[i]<=k的数,第三个存这两个的总个数。如果,mapA.size()>=k/2 and mapB.size()>=k/2 and mapSum.size()>=k就输出YES,else 输出NO。

#include<bits/stdc++.h>
using namespace std;
#define int  long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>
void solve(){
	int n,m,k;
	cin>>n>>m>>k;
	
	vector<int>a(n);
	vector<int>b(m);
	map<int,int>u1;
	map<int,int>u2;
	map<int,int>u;
	for(int i=0;i<n;i++){
		cin>>a[i];
		if(a[i]>=1 and a[i]<=k){
			u1[a[i]]++;
			u[a[i]]++;
		}
		
	}
	for(int i=0;i<m;i++){
		cin>>b[i];
		if(b[i]>=1 and b[i]<=k){
			u2[b[i]]++;
			u[b[i]]++;
		}
	}
	if(u2.size()>=k/2 and u1.size()>=k/2 and u.size()>=k){
		cout<<"YES"<<endl;
	}else{
		cout<<"NO"<<endl;
	}
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	int oyyo=1;
	cin>>oyyo;
	
	while(oyyo--) {
		solve();
	}
	return 0;
}

D. Find the Different Ones!

Problem - D - Codeforces

给你n个数字,m组查询,每次查询[l , r]中是否有l <= i <= rl <= j <= r并且a_i != a_j,如果有输出不同数字的坐标,没有输出两个-1。

数据范围是2*10^5,考虑nlogn以内复杂度,从后向前处理最大的连续相等距离,进行O(n)遍历,O(1)查询。

#include<bits/stdc++.h>
using namespace std;
#define int  long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>
int pos[1000006];
void solve(){
	int n;
	cin>>n;
	vector<int>a(n);
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	
	pos[n-1]=n;//记录最大的连续相等字串长度,最右边的边界是n.
	for(int i=n-2;i>=0;i--){//倒序遍历
		if(a[i]==a[i+1]){
			pos[i]=pos[i+1];//如果这个数和前一个数相同,那么就继承他的最大扩展边界,
		}else{
			pos[i]=i+1;//否则的话,字串连续从他这里更新。
		}
	}
	
	int q;
	cin>>q;
	while(q--){
		int l,r;
		cin>>l>>r;
		l--,r--;
		if(pos[l]>r){//如果输入的有边界小于处理后的连续范围边界,那么这一段就是连续的。
			cout<<-1<<" "<<-1<<endl;
		}else{
			//否则的话,再所给范围内连续就会中断,直接输出最左边和pos[l](他所达到的边界)就好了。
			cout<<l+1<<" "<<pos[l]+1<<endl;
		}
	}
	cout<<endl;
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	int oyyo=1;
	cin>>oyyo;
	
	while(oyyo--) {
		solve();
	}
	return 0;
}

E.Klever Permutation

Problem - E - Codeforces

给你两个数字n和k,问(i + k - 1) <= n每个\sum i - i + k - 1的最大值和最小值相差要小于等于1。输出合法序列。
一次移动1最好,这样永远不会相差超过1,那么第一轮就取右边界一直减,第二轮就取左边界一直加。直到l>=r跳出循环。
#include<bits/stdc++.h>
using namespace std;
#define int  long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>

int a[200005],b[200005];
void solve(){
	int n,m;
	cin>>n>>m;
	int l=1,r=n;
	int rt=1;//记录每次赋值的开头数,每次从这个开头错落赋值。
	while(1){
		if(l>r){
			break;
		}
		for(int i=rt;i<=n;i+=m){
			a[i]=r;//从大开始排
			r--;
		}
		rt++;
		if(l>r){
			break;
		}
		for(int i=rt;i<=n;i+=m){
			a[i]=l;//从小开始排
			l++;
		}
		rt++;//开头赋值点坐标++,
	}
	for(int i=1;i<=n;i++){
		cout<<a[i]<<" ";
	}
	cout<<endl;
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	int oyyo=1;
	cin>>oyyo;
	
	while(oyyo--) {
		solve();
	}
	return 0;
}

D. Rudolf and the Ball Game

Problem - D - Codeforces

鲁道夫和他的健忘朋友。

这个提要良好的使用set容器。【总结】C++ 基础数据结构 —— STL之集合(set)用法详解_std::set-CSDN博客

C++ 之 Vector数组基础用法介绍_c++ vector数组-CSDN博客


(从第二个博客里学的新知识)

这个在一循环进行外(游戏开始前),要先创建一个记录现在可能拿到球的人的数组。

之后进入循环,如果第二字符为’0‘,那么就正序传递并循环(%取模运算),在内部创建一个set集合,用来存储传递过程中可能是接球者的人。每一次判断完后,now数组都要清空,然后把now数组更新为现在的set里的数据,(每次传递继承上一次传递的结果)。等到m次判断完后,现在的now就是最后方案了,直接遍历输出就好了。

这一层的复制起始是没必要的,因为原题解写了,可能是怕有改动的错误。但是这个只是不会。

STL学习——栈,队列,set,优先队列-宣传自己

细节:逆时针旋转要加n再取模。如果是’?‘两个情况都要包含。

#include<bits/stdc++.h>
using namespace std;
#define int  long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>

void solve(){
	int n,m,x;
	cin>>n>>m>>x;//球yuan,投球次数,首个人
	
	vector<int>now(1,x);
	while(m--){
		int r;
		char c;
		set<int>s;
		vector<int>mid(now);//复制构造函数相当于vector<int>mid=now;
		
		cin>>r>>c;
		//set 是一个有序的容器,里面的元素都是排序好的,默认从小到大。
		if(c=='0'){
			for(int c:now){
				if(c+r==n){
					s.insert(n);
				}else{
					s.insert((c+r)%n);
				}
			}
		}else if(c=='1'){
			for(int c:now){
				if(c-r==0){
					s.insert(n);
				}else{
					s.insert((c-r+n)%n);
				}
			}
		}else{
			for(int c:now){
				if(c+r==n){
					s.insert(n);
				}else{
					s.insert((c+r)%n);
				}
				if(c-r==0){
					s.insert(n);
				}else{
					s.insert((c-r+n)%n);
				}
			}
		}
		now.clear();
		for(int c:s){
			now.emplace_back(c);
		}
	}
	cout<<now.size()<<endl;
	for(int c:now){
		cout<<c<<" ";
	}
	cout<<endl;
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	int oyyo=1;
	cin>>oyyo;
	
	while(oyyo--) {
		solve();
	}
	return 0;
}

E. Rudolf and k Bridges

Problem - E - Codeforces

双端队列(Deque)-CSDN博客

题目要求连续造k座桥,那么只需要把每一座桥的建造成本记录一下,最后取其中和最小的连续k座桥的成本即可。

对于每一座桥计算他的建造成本:用dp来做,这座桥的第j个位置的建造成本为dp[j];
dp[j]=dp[k]+a[i][j]+1;其中k是一个范围[j-k-1,j-1];
最后就是一个前缀和来求连续k座桥的成本了。

#include<bits/stdc++.h>
using namespace std;
#define int  long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>

void solve(){
	int n,m,k,d;
	cin>>n>>m>>k>>d;//桥数,支架间最大距离。
	vector<vector<int>>a(n,vector<int>(m));
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cin>>a[i][j];
		}
	}
	vector<int>sum;
	for(int i=0;i<n;i++){
		deque<int>q;
		vector<int>dp(m+1);
		q.push_back(0);//先将陆地上第一个支架放入队列。
		dp[0]=1;//地面上的起点坐标为0,深度也为0,所以起点的价钱是1。
		for(int j=1;j<m;j++){
			while(!q.empty() and j-q.front()-1>d){
				q.pop_front();
				//对于队列的开头,如果两个点的差值大于最大间隔,这个点就没用了,对于之后点的更没用,所以直接弹出。
			}
			dp[j]=dp[q.front()]+a[i][j]+1;
			//这个点的价钱更新。
			while(!q.empty() and dp[j]<dp[q.back()]){
				q.pop_back();//比新来的弱的也直接退掉。 保证下次更新时,都可以是最便宜的价格
			}
			q.push_back(j);//这个点建支架了。插入进去。
		}
		sum.emplace_back(dp[m-1]);//当到末尾的时候,在sum数组里插入最大价格。
	}
	//两个类似的方法求连续的最小和。
//	int pre[n+1];
//	pre[0]=sum[0];
//	for(int i=1;i<sum.size();i++){
//		pre[i]=pre[i-1]+sum[i];
//	}
//	int ss=pre[k-1];
//	for(int i=k;i<sum.size();i++){
//		ss=min(ss,pre[i]-pre[i-k]);
//	}
//	cout<<ss<<endl;
	if(sum.size()==1){
		cout<<sum[0]<<endl;
		return;
	}
	for(int i=1;i<n;i++){
		sum[i]+=sum[i-1];
	}
	int min1=sum[k-1];//把第一个连续K串统计进去,要不会丢掉
	for(int i=k;i<n;i++){
		min1=min(min1,sum[i]-sum[i-k]);
	}
	cout<<min1<<endl;
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	int oyyo=1;
	cin>>oyyo;
	
	while(oyyo--) {
		solve();
	}
	return 0;
}

B. A BIT of a Construction

Problem - B - Codeforces

如果给定的n是1的话,我们没有选择,只能去输出k,如果这个数本身就是2^n-1这样二进制全是1的话我们也直接输出k就好,剩下的所有数全都输出0,加和也不影响。那对于一般情况,我们去计算他的二进制位有几个,然后去输出比它小的满足2^n-1形式的最大数。在输出k-这个数,这就是我们能找到的二进制位1最多的情况,然后其他全部输出0就好。

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

#define int long long
#define PII pair<int,int>
#define endl '\n'
int q_pow(int a, int b)
{
	int res = 1;
	while(b)
	{
		if(b&1) res *= a;
		a *= a;
		b >>= 1;
	}
	return res;
}

int lcm(int a, int b)
{
	return a*b/__gcd(a,b);
}

void solve()
{
	int n,k;
	cin>>n>>k;
	if(n==1)
	{
		cout<<k<<endl;
		return;
	}
	int cnt0=0;
	int t=k;
	int len=0;
	while(t)
	{
		if(t%2==0)
		{
			cnt0++;
		}	
		t/=2;
		len++;
	}
	if(cnt0==0)
	{
		cout<<k<<" ";
		for(int i=1;i<n;i++)
		{
			cout<<0<<" ";
		}
		cout<<endl;
		return;
	}
	int st=(1<<(len-1))-1;
	cout<<st<<" "<<k-st<<" ";
	for(int i=2;i<n;i++)
	{
		cout<<0<<" ";
	}
	cout<<endl;
}

signed main()
{
	ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
	int T;
	cin >> T;
//	T = 1;
	while(T--)
	{
		solve();
	}
	return 0;
}

C. How Does the Rook Move?

Problem - C - Codeforces

当一个n*n的棋盘上放上一个棋子的时候,整行整列的期满都无法被访问,因此棋盘退化为一个(n-1)*(n-1)的棋盘,可以用dp来对答案进行求解,由于电脑会接续你的步骤,那么当你下了(r,c)(r!=c)时,整个棋盘就变成了(n-2)*(n-2)棋盘当你下了(r,c)(r==c)时,电脑无法理解你的操作,会跳过。那么棋盘就会变成一个(n-1)*(n-1)的棋盘,只需要考虑求解就好了,假设第一行第一列是新增的。然后思考第一步放在每个地方的情况,在(1,1)情况下会退化为(i*i)的棋盘,其他情况都是(i-1)*(i-1)的棋盘,所以状态转移方程是dp[i]=dp[i-1]+(i+i-2)*dp[i-2]。然后根须输出判断出k不之后退化为多大的棋盘就好了,dp[i]记录的是 i*i 的棋盘有多少方案数。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>
priority_queue<int,vector<int>,greater<int>>qmi;//大根堆
priority_queue<int>qma;//小根堆
const int mod = 1e09+7;
const int N=5e5+10;
int n,k;
vector<int>a(N,0);
vector<int>dp(N,0);
void solve(){
    cin>>n>>k;
    for(int i=0;i<k;i++)
    {
        int x,y;
        cin>>x>>y;
        if(x==y)
        {
            n-=1;
        }else
        {
            n-=2;
        }
    }
    cout<<dp[n]<<endl;
}
signed main() {
    int t;
    cin>>t;
    //t=1;
    dp[0]=1;
    dp[1]=1;
    dp[2]=3;
    for(int i=3;i<N;i++)
    {
        dp[i]=1*dp[i-1]+(i-1)*2*dp[i-2];
        dp[i]%=mod;
    }
    while(t--) {
        solve();
    }
    return 0;
}

C. Everything Nim

Problem - C - Codeforces

首先,如果是单纯的自然数排序,那么他只会是从第到高依次选其每次只会选1(后面的数会因为前面的选择产生新的1),而如果序列中第一个没出现的数是一个奇数,那么在这个数之后就会是Alice来操作。而Alice可以来操作数的节奏,决定每一个数是剩余1,还是剩余0,最后导致Alice赢,如果是偶数,那么就是Bob赢因为这样就是他来调控比赛的节奏了。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>
priority_queue<int,vector<int>,greater<int>>qmi;//大根堆
priority_queue<int>qma;//小根堆
const int mod = 1e09+7;
const int maxn = 100+10;
int gcd(int a,int b)
{
	return b>0?gcd(b,a%b):a;
}
int lcm(int a,int b)
{
	return a/gcd(a,b)*b;
}
bool cmp(char a,char b)
{
	return a>b;
}
const int N=1e7+10;

void solve(){
	int n;
	cin>>n;
	vector<int>a(n);
	int max1=0;
	unordered_map<int,int>u;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
		max1=max(max1,a[i]);
		u[a[i]]++;
	}
	int max2;
	for(int i=1;i<=max1+1;i++)
	{
		if(u[i]==0)
		{
			max2=i;
			break;
		}
	}
	if(max2>max1)
	{
		if(max1%2==0)
		{
			cout<<"Bob"<<endl;
		}else
		{
			cout<<"Alice"<<endl;
		}
		return ;
	}
	if(max2%2==1)
	{
		cout<<"Alice"<<endl;
	}else{
		cout<<"Bob"<<endl;
	}
}
signed main() {
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	int t=1;
	cin>>t;
	while(t--) {
		solve();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值