Codeforces Round #702 (Div. 3) 題解


本場鏈接:Codeforces Round #702 (Div. 3)

A. Dense Array

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)	

const int N = 55;
int a[N];

int main() 
{
	int T;scanf("%d",&T);
	while(T--)
	{
		int n;scanf("%d",&n);
		forn(i,1,n)	scanf("%d",&a[i]);
		
		int res = 0;
		forn(i,1,n - 1)
		{
			int minv = min(a[i],a[i + 1]),maxv = max(a[i],a[i + 1]);
			while(maxv > 2 * minv)	minv *= 2,++res;
		}
		printf("%d\n",res);
	}
	return 0;
}

B. Balanced Remainders

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)	

int c[3];

int main() 
{
	int T;scanf("%d",&T);
	while(T--)
	{
		int n,x;scanf("%d",&n);
		c[0] = c[1] = c[2] = 0;
		forn(i,1,n)	scanf("%d",&x),++c[x % 3];
		int res = 0;
		while(c[0] != n / 3 || c[1] != n / 3 || c[2] != n / 3)
		{
			if(c[0] > n / 3)	res += c[0] - n / 3,c[1] += c[0] - n / 3,c[0] = n / 3;
			if(c[1] > n / 3)	res += c[1] - n / 3,c[2] += c[1] - n / 3,c[1] = n / 3;
			if(c[2] > n / 3)	res += c[2] - n / 3,c[0] += c[2] - n / 3,c[2] = n / 3;
		}
		printf("%d\n",res);
	}
	return 0;
}

C. Sum of Cubes

思路

枚舉\(b\),由范圍可以知道\(1 \leq b \leq 10^4\).\(a\)可以求一個立方根.如果用浮點數的話需要額外處理邊界一些其他值來避免精度問題.我寫的是整數二分.

代碼

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)	


int main() 
{
	int T;scanf("%d",&T);
	while(T--)
	{
		ll x;scanf("%lld",&x);
		bool ok = 0;
		for(ll b = 1;b <= min(x,10000ll);++b)
		{
			ll a3 = x - b * b * b;
			if(a3 < 0)	break;
			ll l = 1,r = 10000;
			while(l < r)
			{
				ll mid = l + r >> 1;
				if(mid * mid * mid >= a3)	r = mid;
				else l = mid + 1;
			}
			if(l * l * l == a3)
			{
				ok = 1;
				break;
			}
		}
		if(ok)	puts("YES");
		else puts("NO");
	}
	return 0;
}

D. Permutation Transformation

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)	

const int N = 105;
int son[N][2],a[N],depth[N],idx;

int build(int l,int r)
{
	if(l > r)	return 0;
	if(l == r)	return l;
	int root = 0,maxv = 0;
	forn(i,l,r)
	{
		if(a[i] > maxv)
		{
			maxv = a[i];
			root = i;
		}
	}
	son[root][0] = build(l,root - 1),son[root][1] = build(root + 1,r);
	return root;
}

void dfs(int u)
{
	if(son[u][0])	depth[son[u][0]] = depth[u] + 1,dfs(son[u][0]);
	if(son[u][1])	depth[son[u][1]] = depth[u] + 1,dfs(son[u][1]);
}

int main() 
{
	int T;scanf("%d",&T);
	while(T--)
	{
		int n;scanf("%d",&n);
		forn(i,1,n)	scanf("%d",&a[i]),son[i][0] = son[i][1] = 0;
		
		int root = build(1,n);
		depth[root] = 0;
		dfs(root);
		
		forn(i,1,n)	printf("%d ",depth[i]);puts("");
	}
	return 0;
}

E. Accidental Victory

思路

首先次序無所謂,可以先給所有人排序.其次枚舉到第\(i\)個人檢查他是否可以獲勝的時候,他一是可以直接吃掉所有在他左邊的人的分,也就是說對於\(i\)來說他的權應該是\(s[i]\)前綴和,那么現在的問題就是\(s[i]\)是否大於等於\(a[i+1]\),如果是的話\(i\)還可以繼續吃掉\(a[i+1]\)往下走,拿到\(a[i+1]\)的分值等價於把現在的分換成\(s[i + 1]\).接着可以發現\(i\)是否能吃爛分吃掉最后一個人,可以等價於:\(i\)能吃掉\(a[i + 1]\)的分,且從\(i+1\)開始一直能吃到\(n\)的爛分.這個可以后綴與和向前遞推.

代碼

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)	
#define forr(i,x,n)	for(int i = n;i >= x;--i)

typedef pair<int,int> pii;
#define x first
#define y second

const int N = 2e5+7;
pii a[N];
bool win[N];
ll s[N];

int main() 
{
	int T;scanf("%d",&T);
	while(T--)
	{
		int n;scanf("%d",&n);
		forn(i,1,n)	scanf("%d",&a[i].x),a[i].y = i;
		sort(a + 1,a + n + 1);
		
		forn(i,1,n)	s[i] = s[i - 1] + a[i].x;
		forn(i,1,n)	win[i] = (s[i] >= a[i + 1].x);win[n] = 1;
		forr(i,1,n - 1)	win[i] &= win[i + 1];		
		vector<int> res;
		forr(i,1,n)	if(win[i])	res.push_back(a[i].y);
		
		sort(res.begin(),res.end());
		printf("%d\n",(int)res.size());
		for(auto& v : res)	printf("%d ",v);puts("");
	}
	return 0;
}

F. Equalize the Array

思路

枚舉每個數\(C\)表示我想把所有數出現次數拉到C.那么對於所有出現次數小於\(C\)的數來說,我都必須一個一個刪除他們.對於出現次數大於\(C\)的數我可以只刪其中的\(i-C\)個,其中\(i\)表示的是出現次數為\(i\)的某個數對應的出現次數.

簡單來說:需要維護每個數的出現次數,每個數出現次數的出現次數.分別記為cntc_cnt.對於\(<C\)的部分,必須全部刪除,這個求的是有多少個數字,對於\(>C\)的部分,可以刪除$(i-C) * \(出現次數為\)i$的數的種類數.分別前綴和維護就可以了.

代碼

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)	
#define forr(i,x,n)	for(int i = n;i >= x;--i)

const int N = 2e5+7;
int cnt[N],a[N];
int c_cnt_kind[N],c_cnt_num[N];
ll s_c_cnt_kind[N],sj_c_cnt[N],s_c_cnt_num[N];
set<int> st[N];
vector<int> val;

int main() 
{
	int T;scanf("%d",&T);
	while(T--)
	{
		int n;scanf("%d",&n);
		forn(i,0,n)	cnt[i] = 0,sj_c_cnt[i] = 0,st[i].clear(),
		c_cnt_kind[i] = 0,c_cnt_num[i] = 0,s_c_cnt_num[i] = 0,s_c_cnt_kind[i] = 0;
		
		val.clear();
		forn(i,1,n)	scanf("%d",&a[i]),val.push_back(a[i]);
		sort(val.begin(),val.end());
		val.erase(unique(val.begin(),val.end()),val.end());
		forn(i,1,n)	a[i] = lower_bound(val.begin(),val.end(),a[i]) - val.begin() + 1,++cnt[a[i]];
		
		forn(i,1,n)	st[cnt[a[i]]].insert(a[i]);
		forn(i,1,n)	c_cnt_kind[i] = (int)st[i].size(),
					++c_cnt_num[cnt[a[i]]];
		forn(i,1,n)	s_c_cnt_kind[i] = s_c_cnt_kind[i - 1] + c_cnt_kind[i],
					s_c_cnt_num[i] = s_c_cnt_num[i - 1] + c_cnt_num[i],
					sj_c_cnt[i] = sj_c_cnt[i - 1] + c_cnt_kind[i] * i;	
		
		ll res = n;		
		forr(C,1,n)
		{
			ll cur = s_c_cnt_num[C - 1];
			cur += sj_c_cnt[n] - sj_c_cnt[C];
			cur -= C * (s_c_cnt_kind[n] - s_c_cnt_kind[C]);
			res = min(res,cur);
		}
		printf("%lld\n",res);
	}
	return 0;
}

G. Old Floppy Drive

思路

\(a\)求前綴和.考慮分情況:如果一輪就可以拿到\(x\),那么直接在里面lower_bound就可以拿到了.否則一輪結束不了的,看總和是否是正的,如果不是那么無論走多少輪都是無用功.最后一種情況就是找一組\((i,k)\),滿足有\(s[i] + k * sum >= x\).並且\(i+k*n-1\)是最小的.顯然應該先讓\(k\)取到最小值,所以先用最大的\(s[i]\)求出\(k\)的最小值記作\(kmin\),其次要找一個最小的\(i\)使得\(s[i] >= x - kmin * sum\).可以發現如果有\(s[i] > j\)\(i < j\),那么\(j\)的存在是沒有意義的,所以可以對\(s[i]\)求一個前綴max記作premax,由於premax是具有單調性的,所以可以二分求解.

代碼

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n)	for(int i = n;i >= x;--i)

typedef pair<ll,int> pli;
#define x first
#define y second

const int N = 2e5+7;
int a[N],premax[N];
ll s[N];

bool cmp(int x,int y)
{
	return s[x] < y;
}

int main() 
{
	int T;scanf("%d",&T);
	while(T--)
	{
		int n,m;scanf("%d%d",&n,&m);
		forn(i,1,n)	s[i] = 0,premax[i] = 0;
		forn(i,1,n)	scanf("%d",&a[i]),s[i] = s[i - 1] + a[i];
		
		ll sum = s[n];
		premax[1] = 1;
		forn(i,2,n)	premax[i] = (s[premax[i - 1]] < s[i] ? i : premax[i - 1]);
		forn(i,1,m)	
		{
			int x;scanf("%d",&x);
			int p = lower_bound(premax + 1,premax + n + 1,x,cmp) - premax;
			if(p == n + 1)
			{
				if(sum <= 0)	printf("-1 ");
				else
				{
					ll kmin = (x - s[premax[n]] + sum - 1) / sum;
					p = lower_bound(premax + 1,premax + n + 1,x - kmin * sum,cmp) - premax;
					printf("%lld ",p - 1 + kmin * n);
				}
			}
			else printf("%d ",p - 1);
		}
		puts("");
	}
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM