Logo handezheng 的博客

博客

题解:[ABC200D] Happy Birthday! 2

...
handezheng
2025-12-01 12:50:49
崖谷涂足无人问,山巅独饮众生哗。

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2024-09-18 11:18:38

题解:[ABC200D] Happy Birthday! 2

最朴素、最暴力的做法是枚举 $N$ 的全排列,但是因为有 $ N \le 200$,所以这种方法无疑会超时。

这时候我们可以用容斥的思路进行优化。引入抽屉原理

将 $n+1$ 个物体,划分为 $n$ 组,那么有至少一组有两个(或以上)的物体。

因为模数是 200,所以我们只要有 201 个互异的序列,就一定会有两个序列的和同余。而对于长度为 $N$ 的序列,我们可以构造出 $2^N$ 种不同序列。对于 $N\le8$,我们可以暴力取得答案;而对于 $N>8$,因为 $2^8=256>200$,所以一定有答案,我们只需要用前八个元素构造序列,然后用桶存储和判断即可。

代码如下:

#include<bits\/stdc++.h>
#include<vector>
#include<map>
using namespace std;
#define int long long
#define F(i,l,r) for(int i = l;i <= r;i++)

int n,a[205];
map<int,vector<int> > mp;

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	
	cin>>n;
	F(i,1,n){
		cin>>a[i];
		a[i]%=200;
	}
	n=min(n,8ll);
	for(int i=1;i<1<<n;i++){
		vector <int> t;
		int sum=0;
		for(int j=1;j<=n;j++){
			if(i>>(j-1) & 1){
				t.push_back(j);
				sum=(sum+a[j])%200;
			}
		}
		sum%=200;
		if(mp.find(sum)!=mp.end()){
			cout<<"Yes\n"<<mp[sum].size()<<' ';
			for(auto e:mp[sum])	cout<<e<<' ';
			cout<<'\n'<<t.size()<<' ';
			for(auto e:t) cout<<e<<' ';
			return 0;
		}
		mp[sum]=t;
	}
	cout<<"No\n";

	return 0;
}

$2024.9.18$ 完稿

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。