ARC146 部分题解

A
普及组题

// by Balloons
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Madoka"<<endl
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn=2e5+5;

int n;
pair<int,int> a[maxn];

int gt(int x){int t=0;while(x){++t;x/=10;}return t;}

int cmp(pair<int,int> a,pair<int,int> b){
	return a.first == b.first ? a.second > b.second : a.first > b.first;
}

signed main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i].second), a[i].first = gt(a[i].second);
	sort(a+1,a+n+1,cmp);
	if(a[1].first == a[3].first)
		for(int i=1;i<=3;i++){
			printf("%d",a[i].second); 
		}
	else{
		int t1 = a[1].second, t2 = a[2].second, t3 = a[3].second;
		LL p1 = t1*(LL)pow(10,gt(t3)+gt(t2)) + t2*(LL)pow(10,gt(t3))+t3;
		LL p2 = t1*(LL)pow(10,gt(t2)+gt(t3)) + t3*(LL)pow(10,gt(t2))+t2;
		LL p3 = t2*(LL)pow(10,gt(t3)+gt(t1)) + t1*(LL)pow(10,gt(t3))+t3;
		LL p4 = t2*(LL)pow(10,gt(t1)+gt(t3)) + t3*(LL)pow(10,gt(t1))+t1;
		LL p5 = t3*(LL)pow(10,gt(t2)+gt(t1)) + t1*(LL)pow(10,gt(t2))+t2;
		LL p6 = t3*(LL)pow(10,gt(t1)+gt(t2)) + t2*(LL)pow(10,gt(t1))+t1;
		printf("%lld\n",max(max(max(p1,p2),max(p3,p4)),max(p5,p6)));
	}

	return 0;
}

B
由贪心可知异或和为1的位肯定越高位越好,所以从高到低按位扫描,如果当前位为1,不作处理,否则算出将其变为1所需要的最小次数,然后将低位全部置为0。算出每一位的贡献排个序取前k小的,注意即使当前位某个数没被选上也要如此操作因为可能在后面的时候更优,即不只对前k个做上述操作。(也即,当某位确定为1时,所有数都需要该位变为1)

// by Balloons
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#define mpr make_pair
#define debug() cerr<<"Madoka"<<endl
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn=2e5+5;

int n,m,k;
int a[maxn],b[maxn];
LL temp[maxn], lst[maxn];

signed main(){
	LL ans = 0;
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int d = 31;d>=0;d--){
		for(int i=1;i<=n;i++){
			temp[i] = lst[i];
			if((a[i] >> d) & 1);
			else temp[i] += (1ll<<(d)) - (a[i] % (1ll<<(d)));
		}
		sort(temp+1,temp+n+1);
		LL sum = 0;
		for(int i=1;i<=k;i++)sum += temp[i];
		if(sum <= m){
//			printf("?? %d\n",d);
//			for(int i=1;i<=n;i++)printf("%d ",temp[i]);puts("");
			ans |= (1ll<<d);
			for(int i=1;i<=n;i++){
				if((a[i] & (1ll<<d)) == 0){
					lst[i] += ((1ll<<d) - (a[i]%(1ll<<d)));
					a[i] = 0;
				}
			}
		}
	}
	printf("%lld\n",ans);

	return 0;
}

C
题意转化为求\(0~2^n-1\)的子集\(S\)个数,使得\(S\)没有一个子集\(T\)满足:\(T\)大小为偶数且异或和为0
考虑对一个大小为\(i\)的集合来说,有多少的数是加了之后不满足上述条件的?显然我们只需要考虑大小为奇数的子集,如果该子集的异或和为\(p\),则\(p\)显然不能加入集合(注意这就是\(0~2^n-1\)这个条件的运用,p必定也是在该范围内的),现在我只需要统计异或和不同的大小为奇数的集合有多少即可
引理:对于某个集合\(M\),对于其大小为奇数的子集合\(S\ \ T\)如果\(S\)\(T\)不一样,则其异或和必不同
证明:考虑ST并集\(U\),排除2次出现的元素之后大小必为偶数,也必为\(M\)的子集,若ST不一样且异或和相同则\(U\)大小为偶数且异或和为0,\(M\)不符合条件,矛盾
因此,异或和不同的大小为奇数的集合个数 = 大小为奇数的集合个数
\(C(i,1)+C(i,3)+... = 2^{(|S|-1)}\)
考虑dp,设\(dp[i]\)表示大小为i的集合有多少符合条件的,答案即为\(dp[i]\)累加
\(dp[i] = dp[i-1] * (2^n - 2^{((i-1)-1)}) / i\)\(2^(i-2)\)即为大小为\(i-1\)的集合中有多少大小为奇数的集合,除以i是因为有重复,\(dp[i-1]\)中所有方案中的集合,设其中一个集合为\(S\),则S中每一个元素当成"i",S中除了该元素外的集合并上i当成"S",又是一种转移,重复了i次
\(dp[0]=1, dp[1]=2^n\)
显然只需要转移\(n\)次之后就都是0了

// by Balloons
#include <cstdio>
#include <set>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Madoka"<<endl
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f,mod=998244353;

int n;
int pw(int x,int y){
	if(!y)return 1;if(y==1)return x;
	int mid=pw(x,y>>1);
	if(y&1)return 1ll*mid*mid%mod*x%mod;
	return 1ll*mid*mid%mod;
}
int dp[200005];
int cnt,a[20005];
set<int>S;
void dfs(int l,int r){
	if(l == r+1){
		if((cnt&1)){
			int x = 0;
			for(int i=1;i<=cnt;i++)x ^= a[i];
			S.insert(x);
		}
		return ;
	}
	dfs(l+1,r);
	a[++ cnt]=l;
	dfs(l+1,r);
	-- cnt;
}
signed main(){
//	dfs(0,16);
//	printf("%d\n",S.size());	// N = 3, ans = 2^3; N = 4, ans = 2^4
//	return 0;
	scanf("%d",&n);
	dp[0] = 1;
	dp[1] = pw(2,n)%mod;
	LL ans = (dp[0]+dp[1])%mod;
	for(int i=2;i<=n+2;i++){
		dp[i] = 1ll*dp[i-1]*((pw(2,n) - pw(2,i-2)+mod)%mod)%mod*pw(i,mod-2)%mod;
		ans = (ans+dp[i])%mod;
	}
	printf("%d\n",ans);

	return 0;
}
posted @ 2022-09-03 17:13  SkyRainWind  阅读(55)  评论(0编辑  收藏  举报