Codeforces Round 963 (Div. 2)

空気力学の詩發表於2024-08-11

Preface

有懶狗上週日的比賽拖到這週日才寫部落格,我不說是誰

這場比賽的時候因為 C 陣列沒開兩倍卡了 1h 最後寫對拍才看出來,直接心態爆炸導致 D 沒寫完掉大分


A. Question Marks

簽到

#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=405;
int t,n; char s[N];
signed main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		scanf("%d%s",&n,s+1);
		int c[4]={0,0,0,0},ans=0;
		for (RI i=1;i<=4*n;++i)
		if (s[i]!='?') ++c[s[i]-'A'];
		for (RI i=0;i<4;++i) ans+=min(c[i],n);
		printf("%d\n",ans);
	}
	return 0;
}

B. Parity and Sum

注意到偶數與奇數的和依然為奇數,因此我們的策略總是把所有偶數變成奇數

拿出最大的奇數,從小到大和所有偶數比較,能操作就吸收這個偶數得到更大的奇數;否則直接找一個奇數和最大的偶數操作後得到一個最大的數,這個數一定可以和所有偶數進行操作

#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=200005;
int t,n,a[N];
signed main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		scanf("%d",&n); vector <int> odd,even;
		for (RI i=1;i<=n;++i)
		{
			scanf("%d",&a[i]);
			if (a[i]%2==1) odd.push_back(a[i]); else even.push_back(a[i]);
		}
		if (odd.empty()||even.empty()) { puts("0"); continue; }
		sort(odd.begin(),odd.end());
		sort(even.begin(),even.end());
		int flag=0; LL cur=odd.back();
		for (auto x:even) if (cur<x) { flag=1; break; } else cur+=x;
		printf("%d\n",(int)even.size()+flag);
	}
	return 0;
}

C. Light Switches

不難發現燈的狀態以 \(2k\) 為週期變化,因此很容易想到把所有 \(t_i\) 投射到 \([0,2k-1]\) 的陣列上

此時我們需要找到一個長為 \(k\) 的區間 \([l,r]\) 使得其包含所有的數,注意這個區間是在模意義下的可以跨過末尾

最後答案為最小的 \(T\equiv r\pmod {2k}\),且所有的 \(t_i\le T\),簡單列舉即可

#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=200005;
int t,n,k,a[N],c[N*2];
signed main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		scanf("%d%d",&n,&k);
		for (RI i=0;i<2*k;++i) c[i]=-1;
		for (RI i=1;i<=n;++i)
		scanf("%d",&a[i]),c[a[i]%(2*k)]=max(c[a[i]%(2*k)],a[i]);
		vector <int> pos;
		for (RI i=0;i<2*k;++i)
		if (c[i]!=-1) pos.push_back(i);
		if (pos.size()==1) { printf("%d\n",c[pos[0]]); continue; }
		bool flag=0;
		for (RI i=0;i<pos.size()-1;++i)
		{
			int l=pos[i+1],r=2*k+pos[i];
			if (r-l<k)
			{
				int ans=0; for (auto x:pos)
				if (x>=l) ans=max(ans,c[x]+r-x); else ans=max(ans,c[x]+r-2*k-x);
				printf("%d\n",ans); flag=1; break;
			}
		}
		if (!flag)
		{
			int l=pos[0],r=pos.back();
			if (r-l<k)
			{
				int ans=0; for (auto x:pos)
				ans=max(ans,c[x]+r-x);
				printf("%d\n",ans); flag=1;
			}
		}
		if (!flag) puts("-1");
	}
	return 0;
}

D. Med-imize

中位數的處理套路就是二分答案 \(x\),然後將 \(\ge x\) 的數置為 \(1\)\(<x\) 的數置為 \(0\)(置為 \(-1\) 也行),最後就是要使得留下的數的和大於某個定值

假設最後留下了 \(R\) 個數,觀察這些數需要滿足什麼限制,手玩後發現它們下標對 \(k\) 取模的值從左到右一定為 \(1,2,\dots,k\)

因此很容易想到 DP,令 \(f_{i}\) 表示處理了前 \(i\) 個數,且最後選的數下標模 \(k\) 的值和 \(i\bmod k\) 相同的最大權值和,轉移顯然

#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=500005;
int t,n,k,rem,a[N],f[N];
inline int calc(CI lim)
{
	int ret=0; for (RI i=1;i<=n;++i)
	{
		if ((i-1)%k+1>rem) { f[i]=0; continue; }
		if ((i-1)%k==0)
		{
			f[i]=(a[i]>=lim);
			if (i>=k) f[i]=max(f[i],f[i-k]);
		}else
		{
			f[i]=f[i-1]+(a[i]>=lim);
			if (i>=k) f[i]=max(f[i],f[i-k]);
		}
		ret=max(ret,f[i]);
	}
	return ret;
}
signed main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		scanf("%d%d",&n,&k);
		for (RI i=1;i<=n;++i) scanf("%d",&a[i]);
		if (n<=k)
		{
			sort(a+1,a+n+1);
			printf("%d\n",a[(n+1)/2]);
			continue;
		}
		rem=n%k; if (rem==0) rem+=k;
		int l=1,r=1e9,mid,ret;
		while (l<=r) if (calc(mid=l+r>>1)>=rem/2+1) ret=mid,l=mid+1; else r=mid-1;
		printf("%d\n",ret);
	}
	return 0;
}

E. Xor-Grid Problem

觀察到核心性質後就不難的一個題

不妨給矩形多擴充套件一行一列,其中最後一行的數字代表這列所有數字的異或和;最後列的數字代表這行所有數字的異或和

此時不難發現每個操作等價於交換某一行和最後一行,以及交換某一列和最後一列

但我們最後計算答案時不考慮多出的這一行一列,因此需要在選出某行某列刪去後,將剩下的行列任意排布得到答案

不難發現行和列的貢獻可以分開計算,以行為例,任意兩行相鄰排布的貢獻就是它們對應列(去掉被刪除的列後)上元素差的絕對值和

這形成了一個類似哈密頓路徑的問題,可以簡單狀壓 DP 解決,最後將刪去某行某列的答案合併即可

認為 \(n,m\) 同階,總複雜度 \(O(2^n\times n^3)\)

#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=16,INF=1e9;
int t,n,m,a[N][N],dr[N][N],dc[N][N],R[N][N],C[N][N],f[1<<N][N];
inline void solve(int d[N][N],CI n)
{
	for (RI i=0;i<(1<<n+1);++i)
	for (RI j=0;j<=n;++j) f[i][j]=INF;
	for (RI i=0;i<=n;++i) f[1<<i][i]=0;
	for (RI mask=0;mask<(1<<n+1);++mask)
	for (RI i=0;i<=n;++i) if ((mask>>i)&1)
	for (RI j=0;j<=n;++j) if (!((mask>>j)&1))
	f[mask|(1<<j)][j]=min(f[mask|(1<<j)][j],f[mask][i]+d[i][j]);
}
signed main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		scanf("%d%d",&n,&m);
		for (RI i=0;i<=n;++i) a[i][m]=0;
		for (RI j=0;j<=m;++j) a[n][j]=0;
		for (RI i=0;i<n;++i) for (RI j=0;j<m;++j)
		scanf("%d",&a[i][j]),a[i][m]^=a[i][j],a[n][j]^=a[i][j];
		for (RI i=0;i<n;++i) a[n][m]^=a[i][m];
		for (RI rmv_c=0;rmv_c<=m;++rmv_c)
		{
			for (RI i=0;i<=n;++i) for (RI j=0;j<=n;++j)
			{
				if (i==j) continue; dr[i][j]=0;
				for (RI k=0;k<=m;++k)
				if (k!=rmv_c) dr[i][j]+=abs(a[i][k]-a[j][k]);
			}
			solve(dr,n);
			for (RI i=0;i<=n;++i)
			{
				R[i][rmv_c]=INF; int mask=((1<<n+1)-1)^(1<<i);
				for (RI j=0;j<=n;++j)
				if ((mask>>j)&1) R[i][rmv_c]=min(R[i][rmv_c],f[mask][j]);
			}
		}
		for (RI rmv_r=0;rmv_r<=n;++rmv_r)
		{
			for (RI i=0;i<=m;++i) for (RI j=0;j<=m;++j)
			{
				if (i==j) continue; dc[i][j]=0;
				for (RI k=0;k<=n;++k)
				if (k!=rmv_r) dc[i][j]+=abs(a[k][i]-a[k][j]);
			}
			solve(dc,m);
			for (RI i=0;i<=m;++i)
			{
				C[rmv_r][i]=INF; int mask=((1<<m+1)-1)^(1<<i);
				for (RI j=0;j<=m;++j)
				if ((mask>>j)&1) C[rmv_r][i]=min(C[rmv_r][i],f[mask][j]);
			}
		}
		int ans=INF; for (RI i=0;i<=n;++i) for (RI j=0;j<=m;++j)
		ans=min(ans,R[i][j]+C[i][j]); printf("%d\n",ans);
	}
	return 0;
}

F1. Dyn-scripted Robot (Easy Version)

感覺比 D,E 都簡單,算是個經典套路題

對於這類反射類問題一個經典的處理就是不改變機器人的移動方向,而是將整個外框映象一下,這樣就不涉及修改操作序列了

手玩下會發現當機器人走到 \((x,y)\) 時,在原矩形中的位置相當於 \((x\bmod 2w,y\bmod 2h)\)

因此這題很容易求解,我們先求出進行一整個序列的操作後坐標的偏移量 \(\Delta x,\Delta y\),然後列舉之前進行了 \(i\in[0,k-1]\) 次完整的操作

要回到 \((0,0)\) 等價於在某個位置的偏移量為 \((-i\times \Delta x,-i\times \Delta y)\)(模意義下),用 map 統計下即可

#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=1e6+5;
int t,n,k,w,h; char s[N];
signed main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		scanf("%d%d%d%d%s",&n,&k,&w,&h,s+1);
		map <pi,int> rst; int x=0,y=0;
		for (RI i=1;i<=n;++i)
		{
			switch (s[i])
			{
				case 'U': ++y; break;
				case 'D': --y; break;
				case 'R': ++x; break;
				case 'L': --x; break;
			}
			x=(x%(2*w)+2*w)%(2*w);
			y=(y%(2*h)+2*h)%(2*h);
			++rst[{x,y}];
		}
		LL ans=0; for (RI i=0;i<k;++i)
		{
			int dx=(-1LL*i*x%(2*w)+2*w)%(2*w);
			int dy=(-1LL*i*y%(2*h)+2*h)%(2*h);
			ans+=rst[{dx,dy}];
		}
		printf("%lld\n",ans);
	}
	return 0;
}

Postscript

感覺最近不管什麼比賽只要不順心就容易紅溫犯病,明明已經算是老登了心態還是一如既往的爛

今晚還有 Div1+2,週末還要去北京打百度之星的決賽,希望別暴斃地太難看了吧

相關文章