2023CCPC桂林 B C G H I K M

2023CCPC桂林 B C G H I K M

M(二分 + 前缀,签到)

思路:直接二分答案,在check函数内用前缀1,-1,找一个最大区间即可

const int N = 300005;
int a[N],b[N];
int n;
int dp[N];
bool check(int x){
	memset(dp,0,sizeof dp);
	int cnt = 0;
	for(int i = 1;i <= n;i++){
		if(a[i]<x && b[i]>=x) dp[i] = 1;
		if(a[i]>=x && b[i]<x) dp[i] = -1;
		if(a[i]>=x) cnt++;
	}
	int l = 1;
	int tp = 0;
	int mx = 0;
	int ans = 0;
	for(int r = 1;r <= n;r++){
		tp+=dp[r];
		ans = max(tp-mx,ans);
		mx=min(mx,tp);
	}
	cnt+=ans;
	return cnt >= (n/2) + 1;
}
void solve(){
	cin >> n;
	for(int i = 1;i <= n;i++){
		cin >> a[i] >> b[i];
	}
	int l = 1,r = 1e9+7,ans = 0;
	while(l<=r){
		int mid = l + r >> 1;
		if(check(mid)){
			ans = mid;
			l= mid + 1;
		}else{
			r = mid - 1;
		}
	}
	cout << ans;
}

G(思维,签到)

思路:简单的思维模拟,查询每个(能不能匹配到)括号,因为)有右移的作用,答案不用最小字符串,只要构造合法方式就行,其实如果字符串合法,就输出原字符串

string s;
void solve(){
	cin >> s;
	bool f = 0;
	stack<char> st;
	for(auto p :s){
		if(p==')'){
			if(st.size()) {
				st.pop();
			}
		}else{
			st.push('(');
		}
	}
	if(st.size()){
		cout << "impossible" << endl;
	}else{
		cout << s;
		cout << endl;
	}
}
signed main(){
	std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    std::cout.tie(0);
	int times = 1;
	cin >> times;
	while(times--){
		solve();
	}
	return 0;
}

K(思维+模拟,签到/铜牌)

思路:数据量最多min(n!, 2 ^ m),直接set模拟暴力即可


void solve(){
	int n,m;
	cin >> n >> m;
	vt<int> a(n),b(n);
	set<vt<int>> se;
	while(m--){
		for(int i = 0; i<n;i++) cin >> b[i],b[i]--;
		set<vt<int>> se2;
		for(auto &p:se){
			for(int i = 0;i < n;i++){
				a[i] = p[b[i]];
			}
			se2.insert(a);
		}
		se2.insert(b);
		for(auto p:se2) se.insert(p);
	}
	cout << se.size() << endl;
}

B(思维,铜牌)

const int N = 300005;
int n,m;
int a[N],b[N];
struct nodes
{
	int val,op;
	bool operator<(const nodes& n1)const{
		return val > n1.val;
	}
}c[N];
void solve(){
	cin >> n >> m;
	for(int i = 1;i <= n;i++) cin >> a[i],c[i].val = a[i],c[i].op = 0;
	for(int j = 1;j <= m;j++) cin >> b[j];
	sort(a + 1,a + 1 + n);
	for(int i = 1;i <= n;i++) c[i].val = a[i],c[i].op = 0;
	sort(b + 1,b + 1 + m);
	int del = n - m;
	int cnt = 0;
	bool f = 1;
	for(int i = 1;i <= m;i++){
		int id = n - m + i;
		if(a[id] > b[i]) f=0;
		cnt+=b[i]-a[id]; 
		c[id] = {a[id],b[i]};
	}
	if(!f || cnt > del){
		cout << -1 << endl;
		return;
	} 
	priority_queue<nodes> q2,q;
	for(int i = 1;i <= del;i++) q2.push(c[i]);
	for(int i = del + 1;i <= n;i++) q.push(c[i]);
	vt<int> ans;
	f = 1;
	while(cnt < del){
		if(q2.empty()){
			f = 0;
			break;
		}
		nodes p = q2.top();q2.pop();
		ans.pb(p.val);
		++p.val;
		if(p.val > q.top().val){
			cnt--;   //刚好只会超过1个单位
			nodes u = q.top();
			q.pop();
			if(p.val > u.op){ //不能超过
				f = 0;
				break;
			}
			p.op = u.op;
			q2.push(u);
			q.push(p);
		}else{
			q2.push(p);
		}
		del--;
		q2.pop();
	}
	if(!f || cnt > del){
		cout << -1 << endl;
		return;
	}
	while(q.size()){
		nodes p = q.top();q.pop();
		int d = p.op - p.val;
		while(d--){
			ans.pb(p.val);
			p.val++;
		}
	}
	cout << ans.size() << endl;
	for(auto p:ans){
		cout << p << " ";
	}
	cout << endl;
}
signed main(){
	std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    std::cout.tie(0);
	int times = 1;
	cin >> times;
	while(times--){
		solve();
	}
	return 0;
}

I(树状数组+思维(类HH的项链),铜牌/银牌)

const int N = 500005;
int n,m;
int a[N];
vt<int> pos[N];
int idx[N],pre[N];
int cnt[N];
struct Fenwick{
	vector<int> tr;
	int sz;
	void init(int n){
		tr.resize(n + 1);
		sz = n;
	}
	Fenwick(){}
	Fenwick(int n){
		init(n);
	}
	void add(int k,int val){
		for(int i = k;i <= sz;i+=(i&-i)){
			tr[i]+=val;
		}
	}
	int query(int k){
		int res = 0;
		for(int i = k;i > 0;i-=(i&-i)){
			res+=tr[i];
		}
		return res;
	}
	int ask_sum(int l,int r){
		return query(r) - query(l - 1);
	}
};
void solve(){
	cin >> n >> m;
	Fenwick fk(n + 1);

	for(int i = 1;i <= n;i++){
		cin >> a[i];
		cnt[a[i]]=1;
		pos[a[i]].pb(i);
	}
	int ans = -1e9;
	for(int i = 1;i <= n;i++){
		int mex = a[i];
		int r =i - 1;
		int l;
		if(pos[mex][idx[mex]]==i){
			l=0;
		}else{
			l = pos[mex][idx[mex]];
			idx[mex]++;	
		}
		ans = max(ans,fk.query(r)-fk.query(l)-mex);
		if(pre[mex]) fk.add(pre[mex],-1);
		pre[mex] = i;
		fk.add(i,1);
	}
	for(int i = 1;i <= n;i++){
		int mex = a[i];
		int r = n,l = *pos[mex].rbegin();
		ans = max(ans,fk.query(r) - fk.query(l)-mex);
	}
	for(int i = 1;i <= m;i++){
		if(!cnt[i]){
			ans = max(ans,fk.query(n) - i);
			break;
		}
	}
	cout << ans << endl;
	for(int i = 1;i <= n;i++){
		pos[i].clear();
		cnt[a[i]] = 0;
		pre[a[i]] = 0;
		idx[a[i]] = 0;	
	}
}
signed main(){
	std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    std::cout.tie(0);
	int times = 1;
	cin >> times;
	while(times--){
		solve();
	}
	return 0;
}

C(线性基,银牌)

const int N = 200005;
const int mod = 998244353;
struct Lb{
	int lb[61];
	int rank; //多少个线性基,线性基的大小
	void clear(){
		rank = 0;
		for(int i = 0;i <= 60;i++) lb[i] = 0;
	} 
	bool insert(int x){
		for(int i = 60;i>=0;i--){
			if(x>>i&1){
				if(lb[i]==0){
					lb[i]=x;
					rank++;
					return 1; //插入成功
				}
				x^=lb[i];
			}
		}
		return false;
	}
}b[N];
//只有两种可能,一种是总异或为序列的max或者0;
int pw[N];
int n;
int cnt[N],a[N];
int sz[N]; //第i个数有多少个约数 
void solve(){
	cin >> n;
	for(int i = 1;i <= n;i++){
		cin >> a[i];
		cnt[a[i]]++;
	}
	for(int i = 1;i <= n;i++){
		if(cnt[i]){
			for(int j = 0;i*j <= n;j++){
				sz[i*j]+=cnt[i];
				b[i*j].insert(i);
			}
		}
	}
	int ans = pw[n - b[0].rank] - 1; //线性基外元素随便选,但空集不行所以-1
	for(int i = 1; i <= n;i++){
		if(cnt[i]){
			ans = (ans + pw[sz[i] - b[i].rank]) % mod; //i为lcm那么线性基把线性基rank全选,sz是i的约数集合大小,其他可以任意,所以是 2^(sz-rank)
		}
	}
	for(int i =0;i<=n;i++) b[i].clear(),sz[i]=0,cnt[i]=0;
	ans = (ans + mod)%mod;
	cout << ans  << endl; 
}
signed main(){
	std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    std::cout.tie(0);
	int times = 1;
	cin >> times;
	pw[0] = 1;
	for(int i = 1;i < N;i++) pw[i] = pw[i - 1] * 2%mod;
	while(times--){
		solve();
	}
	return 0;
}

H(树形DP+思维,银/金)

const int N = 1000005;
struct edges
{
	int v,ne;
}e[N<<1];
int h[N],idx = 1;
void add(int u,int v){
	e[++idx] = {v,h[u]};
	h[u]=idx;
}
int a[N];
int n,k;
int f[N][2];
int ans = 0;
void dfs(int u,int fa){
	int sum1 = 0,sum0 = 0;//奇偶分类代表到没个点我在此之前的奇最大和偶最大
	for(int i = h[u];i;i=e[i].ne){
		int v= e[i].v;
		if(v==fa) continue;
		dfs(v,u);
		if((k%2==0 && f[v][0]>=k) || (k%2==1 && f[v][1]>=k) ){
			ans++;
			continue;
		}
		int t1 = sum1,t0 = sum0; //临时变量
		if(sum1) t1 = max(t1,f[v][0] + sum1); //偶+奇=奇
		if(f[v][1]) t1 = max(t1,f[v][1] + sum0); //奇+偶=奇

		t0 = max(t0,f[v][0] + sum0); //偶+偶=偶
		if(sum1 && f[v][1])t0 = max(t0,f[v][1] + sum1); //奇+奇=偶

		sum1 = t1,sum0 = t0;
	}
	if(a[u]&1){
		f[u][1] = a[u] + sum0;
		if(sum1) f[u][0] = sum1 + a[u];  
	}else{
		f[u][0] = a[u] + sum0;
		if(sum1) f[u][1] = sum1 + a[u];  
	}

}
void solve(){
	cin >> n >> k;
	idx = 1;
	ans = 0;
	for(int i = 1;i <= n;i++) cin>>a[i],h[i]=0,f[i][0]=0,f[i][1]=0;
	for(int i = 1;i <= n - 1;i++){
		int u,v;
		cin >> u >> v;
		add(u,v);
		add(v,u);
	}
	dfs(1,0);
	if((k%2==0 && f[1][0]>=k) || (k%2==1 && f[1][1]>=k) ){
		ans++;
	}
	cout << ans << endl;
}
signed main(){
	std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    std::cout.tie(0);
	int times = 1;
	cin >> times;
	while(times--){
		solve();
	}
	return 0;
}
posted @ 2025-03-31 10:50  GsGXT  阅读(79)  评论(0)    收藏  举报