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;
}
posted @ 2022-05-03 21:32  zyy2001  阅读(64)  评论(0编辑  收藏  举报