codeforces round 912 (A - D)补题记录

A Halloumi Boxes

翻译

有一个由 n n n 个数组成的数组,每个数为 a i a_i ai

你可以随意翻转这个数组中长度不超过 k k k 的子数组,求是否可以通过翻转使数组按不递减的顺序排序,是输出"YES"(不区分大小写),否输出"NO"(不区分大小写)。

有多组测试数据。

题解:

只要k不为1,则都能翻转成功;
若k为1,则检查是否本身不递减

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

int t,a,b,flag;

int main ()
{
	cin >> t;
	while(t --)
	{
		cin >> a >> b;
		flag = 0;
		int temp1,temp2;
		cin >> temp1;
		a--;
		while(a --)
		{
			cin >> temp2;
			if(temp2 < temp1)flag = 1;
			temp1 = temp2;
		}
		b > 1 || flag == 0 ? cout << "YES\n" : cout << "NO\n" ;
	}
	return 0;
}

B StORage room

翻译

有一个 n × n n \times n n×n 的矩阵 M M M。你的任务就是找出一个数组 a a a,使得 a i ∣ a j = M i , j a_i \mid a_j=M_{i,j} aiaj=Mi,j(其中 i ≠ j i \ne j i=j ∣ \mid 表示[按位或]

T T T 组数据,每组数据先输入一个 n n n,然后 n n n 行,每行 n n n 个数,表示矩阵 M M M

对于每组测试数据,如果存在解决方案,输出 YES 和满足该属性的数组(如果有多种满足的数组,输出任意一种)。如果不存在解决方案,输出 NO

题解

我们已知 M i , j M_{i,j} Mi,j的是由 a i a_i ai a j a_j aj得来;
求出a,再验证是否满足

#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N = 1e3 + 10;

int a[N][N];
int ans[N];
int t,n;
int flag;

int main ()
{
	cin >> t;
	while(t --)
	{
		cin >> n;
		flag = 0;
		memset(ans,-1,sizeof(ans));
		for(int i = 1;i <= n;++ i)
		{
			for(int j = 1;j <= n;++ j)
			{
				cin >> a[i][j];
			}
		}
		
		for(int i = 1;i <= n;++ i)
		{
			for(int j = 1; j <= n;++ j)
			{
				if(j == i)continue;
				
				if(ans[i] == -1)ans[i] = a[i][j];
				else {
					ans[i] &= a[i][j];
				}
			}
		}
		
		for(int i = 1;i <= n && flag == 0;++ i)
		{
			for(int j = 1;j <= n && flag == 0;++ j)
			{
				if(i == j)continue;
				if((ans[i] | ans[j]) != a[i][j])
				{
					flag = 1;
					cout << "NO\n";
				}
			}
		}
		if(flag == 0){
			cout << "YES\n";
			for(int i = 1;i < n;++ i)
			{
				cout << max(ans[i] ,0)<< " ";
			}
			cout << max(ans[n] ,0) << "\n";
		}
		
	}
	return 0;
}

C Theofanis’ Nightmare

翻译

你需要将一个长度为 n n n 的数列分为若干段。设你分了 k k k 段,第 i i i 段的数的和为 s i s_i si,你需要最大化 ∑ i = 1 k i × s i \sum_{i=1}^ki\times s_i i=1ki×si 的值。

n ≤ 1 0 5 , ∣ a i ∣ ≤ 1 0 8 n\leq 10^5,|a_i|\leq 10^8 n105,ai108

题解

首先解决 ∑ i = 1 k i × s i \sum_{i=1}^ki\times s_i i=1ki×si 这里乘i,变可以通过加 i 次 s [i]解决;然后就是划分区段只要,这个区段大于0则单独作为区段,若小于0,则想办法给他加成大于0的。

#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N = 1e5 + 10;

LL t,n,temp;
LL a[N],ans;

int main ()
{
	cin >> t;	
	while(t --)
	{
		cin >> n;
		ans = 0;
		for(int i = 1;i <= n;++ i)
		{
			cin >> a[i];
			ans += a[i];
		}
		
		temp = 0;
		for(int i = n;i >= 2;-- i)
		{
			temp += a[i];
			if(temp > 0)
			{
				ans += temp;
			}
			
		}
		cout << ans << "\n";
	}
	return 0;
}

D Maximum And Queries (easy version)

翻译

给定长度为 n n n 的序列 a a a,定义一次操作是选择一个 i i i,令 a i ← a i + 1 a_i \gets a_i + 1 aiai+1

q q q 次询问,每次给定 k k k,求出最多进行 k k k 次操作后,整个序列按位与的最大值,即最大化

AND ⁡ i = 1 n a i \operatorname{AND}_{i=1}^n a_i ANDi=1nai

数据范围 1 ≤ n ⋅ q ≤ 1 0 5 1 \le n \cdot q \le 10^5 1nq105

题解

从这个 1 ≤ n ⋅ q ≤ 1 0 5 1 \le n \cdot q \le 10^5 1nq105入手,题目中最大 10^5 + 10^18 < 2^60
从最高位开始,看当前所有数据能否在所有代价加起来小于q的情况下满足该位为1;

#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N = 1e5 + 10;

int n,t;
LL a[N],b[N],ans[110];
LL k;

LL O_o(LL x,LL y)
{
	LL cost = 0;
	for(int i = 1;i <= n;++ i)
	{
		if((b[i] & ((LL)1 << x)) == 0)
		{
			cost += ((LL)1 << x) - (((1ll << (x + 1)) - 1ll) & b[i]);
		}
		if(cost > y)return cost;
	}
	return cost;
}


int main ()
{
	ios :: sync_with_stdio(0),cin.tie(0);
	cin >> n >> t;
	for(int i = 1;i <= n;++ i)
	{
		cin >> a[i];
	}
	while(t --)
	{
		cin >> k;
		memcpy(b,a,(n + 1) * sizeof(LL)); //这里如果sizeof(b)测试4会爆时间
//		for(int i = 1;i <= n;++ i)
//		{
//			b[i] = a[i];
//		}
		memset(ans,0,sizeof(ans));
		
		for(int i = 66;i >= 0;-- i)
		{
			LL temp = O_o(i,k);
			if(temp <= k)
			{
				ans[i] = 1;
				k -= temp;
				for(int j = 1;j <= n;++ j)
				{
					if((b[j] & (1ll << i)) == 0)
					{
						b[j] = ((b[j] | (1ll << i)) & (1ll << i));
					}
				}		
			}
		}
		LL re = 0;
		for(int i = 0;i <= 66;++ i)
		{
			re |= (ans[i] << i);
		}
		cout << re << "\n";
	}	
	return 0;
}

这道题这个做法就很暴力,D2就不适用这方法

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值