codeforces round 922 (div. 2) A-D

前言:

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

Codeforces Round 922 (Div. 2) VP记录

传送门

A. Brick Wall

就是一张 \(n*m\) 的地图,问你最多可以铺几块 \(1*k\) \((k \ge 2)\) 的地板,并且方向固定不能旋转,那么贪心的想肯定是取 \(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\) 数组也要交换,做的时候并没有想到严谨的做法,懵逼状态下猜出大概的正解了。

其实贪心的想,就是你只在 $ a_i \gt a_j $ 并且 $ b_i \gt b_j $时交换 \(i\)\(j\) 两个下标就可以了。处理也比较简单。

代码:

#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\) ,求 $|({a \oplus x}) - ({b \oplus x})| $,\(0 \leq x \leq r\) 。那么我们可以将 \(a\)\(b\) 都化作二进制,最多也就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 @ 2024-01-31 10:12  call_of_silence  阅读(76)  评论(2编辑  收藏  举报