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} ai∣aj=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 n≤105,∣ai∣≤108。
题解
首先解决 ∑ 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 ai←ai+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 1≤n⋅q≤105。
题解
从这个
1
≤
n
⋅
q
≤
1
0
5
1 \le n \cdot q \le 10^5
1≤n⋅q≤105入手,题目中最大 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就不适用这方法
794





