AtCoder Beginner Contest 216

C - Many Balls

初始数字为 \(0\), 你可以选择对这个数进行两种操作:\(A : +1\)\(B: *2\),给出一组到达 \(n\) 的操作序列(长度最大 \(120\))。

转化成从 \(n\)\(-1\)\(/2\)\(0\), 偶数做 \(/2\), 奇数做 \(-1\), \(log(10^{18}) \approx 60\), 操作数最多不会超过 \(120\)

Sample Code (C++)
int main()
{
	IOS; LL n; cin >> n;
	vector<char> v;
	while(n)
	{
		if(n & 1) v.push_back(‘A‘), n -= 1;
		else v.push_back(‘B‘), n /= 2; 
	}
	reverse(v.begin(), v.end());
	for(auto c : v) cout << c;
	cout << endl;
	return 0;
} 

D - Pair of Balls

\(n\) 种颜色的球,每种有两个,按一定顺序放在 \(m\) 个瓶子中,若某两个瓶子最上方的两个球颜色相同,则可以同时取掉,问是否可以把球取完。

每种颜色转化成一个点,然后做有向图拓扑判环即可

Sample Code (C++)
int n, m;
vector<int> G[N];
int d[N];

int main()
{
	IOS; cin >> n >> m;
	for(int i = 1; i <= m; ++ i)
	{
		int k, pre = 0; cin >> k;
		for(int j = 1; j <= k; ++ j)
		{
			int x; cin >> x;
			if(pre) G[pre].push_back(x), d[x] ++;
			pre = x;
		}
	}
	queue<int> q;
	for(int i = 1; i <= n; ++ i)
		if(!d[i]) q.push(i);
	int res = 0;
	while(!q.empty())
	{
		int u = q.front(); q.pop(); res ++;
		for(auto v : G[u])
		{
			d[v] --;
			if(!d[v]) q.push(v);
		}
	}	
	if(res == n) cout << "Yes" << endl;
	else cout << "No" << endl;
	return 0;
} 

E - Amusement Park

\(n\) 个数,取 \(k\) 次,每个数取完之后 \(-1\) , 求可以取得的最大值。

贪心从最大的开始取,将 \(a\) 从大到小排序后,判断剩余次数是否够前 \(i\)\(a_i\) 取至 \(a_{i + 1}\) , 分类讨论即可

Sample Code (C++)
LL n, m, a[N];

int main()
{
	cin >> n >> m;
	for(int i = 1; i <= n; ++ i) cin >> a[i];
	LL res = 0;
	sort(a + 1, a + n + 1); reverse(a + 1, a + n + 1);
	for(int i = 1; i <= n; ++ i)
	{
		if((a[i] - a[i + 1]) * i <= m)
		{
			res += (a[i] + a[i + 1] + 1) * (a[i] - a[i + 1]) / 2 * i;
			m -= (a[i] - a[i + 1]) * i;
		}
		else 
		{
			int t = m / i;
			res += t * (a[i] + a[i] - t + 1) / 2 * i;
			res += (m % i) * (a[i] - t); 
			break;
		}
	}
	cout << res << endl;
	return 0;
} 

F - Max Sum Counting

给长度为 \(n\) 的序列 \(A = (A_1, A_2, ..., A_n)\), \(B = (B_1, B_2, ... , B_n)\), 求集合 \(S\) 的方案数,使得:\(\max\limits_{i \in S}A_i\ge \sum\limits_{i \in S}B_i\)

\(A\) 按升序排序,每次将当前 \(A_i\) 作为最大的 \(A_i\), 对 \(B\) 做背包统计方案数

Sample Code (C++)
int n;
PII a[N];
int dp[N];

int main()
{
	IOS; cin >> n;
	for(int i = 1; i <= n; ++ i) cin >> a[i].fi;
	for(int i = 1; i <= n; ++ i) cin >> a[i].se;
	sort(a + 1, a + n + 1);
	int res = 0;
	dp[0] = 1;
	for(int i = 1; i <= n; ++ i)
	{
		for(int j = a[i].se; j <= a[i].fi; ++ j)
		{
			res += dp[j - a[i].se];
			if(res > P) res -= P;
		}
		for(int j = 5000; j >= a[i].se; -- j)
		{
			dp[j] += dp[j - a[i].se];
			if(dp[j] > P) dp[j] -= P;
		}
	}
	cout << res << endl;
	return 0;
} 

G - 01Sequence

构造长度为 \(n\)\(01\) 串, 满足 \(m\)\((l, r, x)\) 的限制,即区间 \([l, r]\) 至少有 \(x\)\(1\), 构造一种 \(1\) 最少的方案。

贪心按照右端点排序,并从右端点开始填 \(1\) , 使得填上的 \(1\) 尽可能同时满足多个限制,结合树状数组统计区间 \(1\) 的个数,并查集找最靠右端点的下一个可填 \(1\) 的位置,复杂度 \(O(nlogn)\)

Sample Code (C++)
int n, m, a[N];
struct Node
{
	int l, r, x;
	bool operator < (const Node& t) const 
	{
		return r < t.r;
	}
}q[N];
int fa[N], tr[N];

int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }

int lowbit(int x) { return x & -x; }

void add(int x) { for(int i = x; i <= n; i += lowbit(i)) tr[i] ++; }

int sum(int x) 
{
	int res = 0; 
	for(int i = x; i; i -= lowbit(i)) res += tr[i]; 
	return res;	
}

int main()
{
	IOS; cin >> n >> m;
	for(int i = 1; i <= n; ++ i) fa[i] = i; 
	for(int i = 1; i <= m; ++ i) cin >> q[i].l >> q[i].r >> q[i].x;
	sort(q + 1, q + m + 1);
	for(int i = 1; i <= m; ++ i)
	{
		int one = q[i].x - (sum(q[i].r) - sum(q[i].l - 1));
		for(int j = 1; j <= one; ++ j)
		{
			int now = find(q[i].r); 
			add(now); 
			a[now] = 1;
			fa[now] = find(now - 1);
		}
	}
	for(int i = 1; i <= n; ++ i) cout << a[i] << " ";
	cout << endl;
	return 0;
}  

AtCoder Beginner Contest 216

上一篇:程序挂了之后别再跟我说让我帮你重启啦! 让supervisor帮你搞定...


下一篇:对象拷贝工具类BeanCopier