SMU 2024 ptlks的周报Week 10 (7.22-7.28)

这周学了SOSdp,学会了感觉还挺简单的。核心就几行代码:

//#include <bits/stdc++.h>
for (int j = 0; j < k; j++) {
	for (int i = 0; i < (1 << k); i++) {
		if ((i & (1 << j))) {
			dp[i] += dp[i ^ (1 << j)];
		}
	}
}

基本思路就是按照子集来dp。

E. Compatible Numbers

题意:给定数组,对每个数找出数组中与它互斥的数(AND为0)。

思路:板子题,按子集dp即可

代码

#include <bits/stdc++.h>
//#define int long long
#define mod 998244353
#define PII pair<int,int>
#define PIII pair<int,PII>
#define double long double
#define endl '\n'


using namespace std;

const int N = 1e6 + 10, SZ = (N) << 2;


int mx = 0;
int n = 1e5, k, m = 1e5;
vector<PII>g[N];
int fa[N];
int a[N];
int xx[4] = {0, 1, 0, -1}, yy[4] = {-1, 0, 1, 0};
int dp[1 << 22];
void solve() {
	cin >> n ;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		dp[a[i]] = a[i];
	}
	for (int j = 0; j < 22; j++) {
		for (int i = 0; i < (1 << 22); i++) {
//		cout<<i<<endl;
			if ((i & (1 << j)) && dp[i ^ (1 << j)]) {
				dp[i] = dp[i ^ (1 << j)];
				
			}
		}
	}
	for (int i = 1; i <= n; i++) {
		int j =( a[i] ^ ((1 << 22) - 1));
//		cout<<j<<endl;
//		cout<<a[i]<<' '<<dp[j]<<endl;
		if (dp[j]) {
			cout << dp[j] << ' ';
		} else {
			cout << -1 << ' ';
		}
	}
}

int32_t main() {
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int T = 1;
//	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}

E - Or Plus Max

题意:给定长度为\(2^n\)的序列,对于每个\((1\leq k\leq 2^n-1)\)找出最大的\(a_i+a_j(i\,or\,j\leq k,0\leq i<j<2^n)\)并输出。

思路:dp维护k子集内的最大值和次大值。

代码

#include <bits/stdc++.h>
//#define int long long
#define mod 998244353
#define PII pair<int,int>
#define PIII pair<int,PII>
#define double long double
#define endl '\n'


using namespace std;

const int N = 1e6 + 10, SZ = (N) << 2;


int mx = 0;
int n = 1e5, k, m = 1e5;
vector<PII>g[N];
int fa[N];
int a[N];
int xx[4] = {0, 1, 0, -1}, yy[4] = {-1, 0, 1, 0};
int dp[1 << 22][2];
void solve() {
	cin >> n ;
	for (int i = 0; i <(1<<n); i++) {
		cin >> a[i];
		dp[i][0]=a[i];
	}
	for (int j = 0; j < 22; j++) {
		for (int i = 0; i < (1 << 22); i++) {
//		cout<<i<<endl;
			if ((i & (1 << j))) {
				if(dp[i][0]<dp[i^(1<<j)][0]){
					dp[i][1]=dp[i][0];
					dp[i][0]=dp[i^(1<<j)][0];
					if(dp[i][1]<dp[i^(1<<j)][1]){
						dp[i][1]=dp[i^(1<<j)][1];
					}
				}else if(dp[i][0]>=dp[i^(1<<j)][0]&&dp[i^(1<<j)][0]>dp[i][1]){
					dp[i][1]=dp[i^(1<<j)][0];
				}
				
			}
		}
	}
	int mx=0;
	for (int i = 1; i <(1<<n); i++) {
		mx=max(dp[i][0]+dp[i][1],mx);
		cout<<mx<<endl;
	}
}

int32_t main() {
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int T = 1;
//	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}

D. Cases

题意:给定字符串,字符串由若干个长度不大于k的单词组成,求单词末尾组成的集合大小的最小值。

思路:设单词末尾组成的集合为T,不难得出,字符串中每k个连续字符至少有一个字符与T相交,设这k个连续字符组成的集合为B,则\(T \cap\complement _U B=\varnothing\),考虑将所有\(\complement _U B\)的子集标记,对所有未标记的T的大小取最小值即可。

代码

#include <bits/stdc++.h>
//#define int long long
#define mod 998244353
#define PII pair<int,int>
#define PIII pair<int,PII>
#define double long double
#define endl '\n'


using namespace std;

const int N = 5e5 + 10, SZ = N << 2;


int mx = 0;
int n = 1e5, k, m = 1e5,c;
vector<PII>g[N];
int fa[N];
int a[N];
int xx[4] = {0, 1, 0, -1}, yy[4] = {-1, 0, 1, 0};
int fac[33];

int qpow(int x,int n){
	int ans=1;
	while(n){
		if(n&1){
			ans*=x;
			ans%=mod;
		}
		x*=x;
		x%=mod;
		n>>=1;
	}
	return ans;
}
int C(int n,int m){
	return fac[n]*qpow(fac[m],mod-2)%mod*qpow(fac[n-m],mod-2);
}

int dp[N];
int cnt[20];

void solve() {
	cin >> n>>c  >>k;
	int s=1;
	for(int i=1;i<=n;i++){
		char x;
		cin>>x;
		a[i]=x-'A';
	}
	for (int j = 0; j < c; j++) {
		cnt[j]=0;
		for (int i = 0; i < (1 << c); i++) {
			dp[i]=0;
		}
	}
	
	int p=0;
	for(int i=1;i<=k;i++){
		cnt[a[i]]++;
		p|=(1<<a[i]);
	}
	int msk=(1<<c)-1;
	dp[msk^p]=1;
	for(int i=k+1;i<=n;i++){
		cnt[a[i-k]]--;
		if(!cnt[a[i-k]])p^=(1<<a[i-k]);
		cnt[a[i]]++;
		p|=(1<<a[i]);
		dp[msk^p]=1;
	}
	int mn=c;
	for (int j = 0; j < c; j++) {
		for (int i = 0; i < (1 << c); i++) {
			if ((i & (1 << j))) {
				dp[i ^ (1 << j)]|=dp[i];
				
			}
		}
	}
	for (int i = 0; i < (1 << c); i++) {
		if(i&(1<<a[n]))
		if (!dp[i]) {
			mn=min(mn,__builtin_popcount((unsigned)i));
			
		}
	}
	cout<<mn<<endl;
}

int32_t main() {
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int T = 1;
	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2024-07-28 17:34  ptlks  阅读(17)  评论(0编辑  收藏  举报