Codeforces Round #786 (Div. 3)
比赛链接
Codeforces Round #786 (Div.3)
E. Breaking the Wall
给定一个长度为 \(n\left(2 * 10^{5}\right)\) 的数组,每次操作你可以选择一个下标 \(i\) ,然后令 \(a[i]\) 减 2 , \(a[i-1], a[i+1]\) 减 1 。求最少多少次操作可以使得数组至少出现两个小于等于 0 的数。
解题思路
分类讨论
讨论两个数最终变为小于等于 \(0\) 的位置:
-
两数相隔一个位置
先通过中间的数使两数减少,直到两数中有一个数减少为 \(0\),再单独使另外一个数减少为 \(0\) -
两数相隔不止一个位置
直接统计每个位置单独处理的最小值,选择最小的两个值 -
两数相邻
设两数为 \(t1,t2\),其中 \(t1>t2\),
如果 \(t1\geq 2\times t2\),则答案为 \(\left \lceil \frac{t1}{2} \right \rceil\),否则由于每次操作最多减少 \(3\),总的数为 \(t1+t2\),为了使其不浪费操作次数,每次使大的减少 \(2\),小的减少 \(1\),浪费的值不超过 \(2\),这样操作次数为 \(\left \lceil \frac{t1+t2}{3} \right \rceil\)
代码
// Problem: E. Breaking the Wall
// Contest: Codeforces - Codeforces Round #786 (Div. 3)
// URL: https://codeforces.com/contest/1674/problem/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=2e5+5;
int n,a[N],res=0x3f3f3f3f,b[N];
int main()
{
help;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i],b[i]=(a[i]+1)/2;
sort(b+1,b+1+n);
res=min(res,b[1]+b[2]);
for(int i=1;i<=n;i++)
{
if(i-1>=1&&i+1<=n)
{
int t1=min(a[i-1],a[i+1]),t2=max(a[i-1],a[i+1]);
int t=t1;
t2-=t;
t+=(t2+1)/2;
res=min(res,t);
}
if(i-1>=1)
{
int t1=a[i-1],t2=a[i];
if(t1<t2)swap(t1,t2);
if(t1>=2*t2)res=min(res,(t1+1)/2);
else
res=min(res,(t1+t2+2)/3);
}
if(i+1<=n)
{
int t1=a[i+1],t2=a[i];
if(t1<t2)swap(t1,t2);
if(t1>=2*t2)res=min(res,(t1+1)/2);
else
res=min(res,(t1+t2+2)/3);
}
}
cout<<res<<'\n';
return 0;
}
F. Desktop Rearrangement
给定一个 \(n * m(n, m \leq 1000)\) 的网格,每个格子上都是 \(*\) 或者 \(\cdot\) 。
现在有 \(q\left(q \leq 2 * 10^{5}\right)\) 次询问。每次询问将一个格子进行反转, \(*\) 变成 \(\cdot\) , 变成 \(*\) 。
问将所有的 \(*\) 都进行紧凑操作,最少需要移动多少个 \(*\) 。
紧凑操作为:将 \(*\) 都按照一列一列的放好。
解题思路
模拟
统计总的格子为 \(*\) 的数量 \(sum\),以及当前按要求排好的格子中 \(*\) 的数量 \(cnt\),则移动次数为 \(sum-cnt\)
代码
// Problem: F. Desktop Rearrangement
// Contest: Codeforces - Codeforces Round #786 (Div. 3)
// URL: https://codeforces.com/contest/1674/problem/F
// Memory Limit: 256 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=1005;
int n,m,q,sum,cnt;
char g[N][N];
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)scanf("%s",g[i]+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)sum+=(g[i][j]=='*');
int row=0,col=1;
int t=sum;
while(t--)
{
row++;
if(row==n+1)col++,row=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(j<col)cnt+=(g[i][j]=='*');
else if(j==col&&i<=row) cnt+=(g[i][j]=='*');
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
if(g[x][y]=='.')
{
g[x][y]='*';
sum++;
row++;
if(row==n+1)col++,row=1;
if(y<col||(y==col&&x<=row))cnt++;
if(!(x==row&&y==col))cnt+=(g[row][col]=='*');
}
else
{
cnt-=(g[row][col]=='*');
g[x][y]='.';
sum--;
row--;
if(row==0)col--,row=n;
if(y<col||(y==col&&x<=row))cnt--;
}
printf("%d\n",sum-cnt);
}
return 0;
}