codeforces round 922 (div. 2) A-D

前言:

打的VP,真实实力应该是够我做到前三题。按照同层次的比下去,我们学校估计明年就有人AK IOI了\se\se。昨天水课的时候感觉自己日益颓废ing。

Codeforces Round 922 (Div. 2) VP记录

传送门

A. Brick Wall

就是一张 nm 的地图,问你最多可以铺几块 1k (k2) 的地板,并且方向固定不能旋转,那么贪心的想肯定是取 k=2,那么答案就是 n(m/2)

代码:

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cstdio>
#define int long long
using namespace std;
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x>y?y:x;}
const int M=1;
int T,n,m;
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>T; 
	while(T--)
	{
		cin>>n>>m;
		cout<<n*(m/2)<<"\n";
	}
	return 0;
}

B. Minimize Inversions

题意是你需要让两个数组的逆序对总数最少,你可以交换无数次,但是每次交换的时候 a 数组交换了 b 数组也要交换,做的时候并没有想到严谨的做法,懵逼状态下猜出大概的正解了。

其实贪心的想,就是你只在 ai>aj 并且 bi>bj时交换 ij 两个下标就可以了。处理也比较简单。

代码:

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cstdio>
#define int long long
using namespace std;
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x>y?y:x;}
const int M=2e5+5;
int T,n;
int a[M],b[M],c[M];

inline bool cmp(int x,int y)
{
	return a[x]<a[y];
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>T;
	while(T--)
	{
		cin>>n;
		for(int i=1;i<=n;i++) cin>>a[i];
		for(int i=1;i<=n;i++) cin>>b[i];
		for(int i=1;i<=n;i++) c[i]=i;
		sort(c+1,c+n+1,cmp);
		for(int i=1;i<=n;i++) cout<<a[c[i]]<<" ";
		cout<<"\n";
		for(int i=1;i<=n;i++) cout<<b[c[i]]<<" ";
		cout<<"\n";
	}
	return 0;
}

C. XOR-distance

我觉得我的代码应该是实现起来最简单的一个(VP的时候调了半天),给定 a , b , r ,求 |(ax)(bx)|0xr 。那么我们可以将 ab 都化作二进制,最多也就60位(这里你可能需要用1ll来进行位运算)。

对于两个数的每一位,如果这一位上两个数相同,那么由于最后两个数是要相减的,最后会变为0,那么可以直接跳过。着重要讨论的是这一位不同。首先设 a 为较大数,由于这一位上两个数不同,最后异或上 r 后两数这一位也还是不同。那么贪心的想,从高位向低位,扫到第一位不同的就跳过,相当于是让给了 a,之后再有不同的情况,如果这一位上 a 是1,可以减你就减(毕竟还有 r 的限制)。

代码:

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<vector>
#define int long long
using namespace std;
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x>y?y:x;}
const int M=1e5+5;
int T,a,b,r;
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>T;
	while(T--)
	{
		cin>>a>>b>>r;
		if(a<b) swap(a,b);
		int ans=0,flag=0;
		for(int i=(1ll<<60);i;i>>=1)
		{
			int opt1=i&a,opt2=i&b;
			if(opt1==opt2) continue;
			if(flag==0)
			{
				flag=1;continue;//让出一位 
			}
			if(opt1&&i<=r) a-=i,b+=i,r-=i;//此时 a这一位是1,b这一位是0
		}
		cout<<a-b<<"\n";
	}
	return 0;
}

D. Blocking Elements

我自觉没有实力可以在oi赛制下把这道题切了,我谔谔。

很显然可以想出二分答案,一开始我是遍历整个数组,如果大于了判定值,那么就分段(假的不能再假了),这题显然不是贪心。那么我们就需要设计以第 i 个数作为一段结尾的状态转移,每次枚举前面的某个点作为上一段结尾,然后使用队列&前缀和维护。

哦,还要开long long。

代码:

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cstdio>
#define int long long
using namespace std;
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x>y?y:x;}
const int M=1e5+5;
int T,n,sum=0,maxx=0;
int a[M],s[M],q[M],f[M];
inline int check(int x)
{
	int l=1,r=1;
	q[r++]=0,f[1]=a[1];//记录每一段
	q[r]=1;
	for(int i=2;i<=n;i++)
	{
		while(s[i-1]-s[q[l]]>x) l++;
		f[i]=a[i]+f[q[l]];
		while(r>=l&&f[q[r]]>=f[i]) r--;
		q[++r]=i;//又成一段结尾 
	}
	while(s[n]-s[q[l]]>x) l++;
	if(f[q[l]]<=x) return 1;
	else return 0;
	
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>T;
	while(T--)
	{
		cin>>n;sum=maxx=0;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i],sum+=a[i],maxx=max(maxx,a[i]);
			s[i]=s[i-1]+a[i];
		}
		int l=maxx,r=sum;
		while(l<r)
		{
			int mid=(l+r)>>1;
			if(check(mid)) r=mid;
			else l=mid+1;
		}
		cout<<l<<"\n";
	}
	return 0;
}
posted @   call_of_silence  阅读(97)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示