제출 #1328128

#제출 시각아이디문제언어결과실행 시간메모리
1328128model_codeConference (JOI25_conference)C++20
100 / 100
545 ms33144 KiB
#include <iostream>
#include <cstring>
#include <cassert>
#include <vector>
#include <set>
#include <stack>
#include <algorithm>
#include <bitset>
using namespace std;

using B = bitset<300005>;

int main(){
	int n;
	string s;
	cin>>n>>s;
	
	vector<int> len[6];
	vector<int> rui[6];
	vector<int> two[3][2];
	vector<int> subset_dp[3];
	vector<int> subset_rmq[3];
	vector<int> cnt_up_len[3];
	vector<int> cnt_up_two[3][2];
	int adj = 0;
	
	vector<pair<int,int>>ch;
	for(int i=0;i<n;i++){
		if(s[i] != '?'){
			ch.emplace_back((s[i]-'A'), i);
		}
	}
	for(int i=1;i<(int)ch.size();i++){
		int L = ch[i].second - ch[i-1].second - 1;
		int pre = ch[i-1].first;
		int nxt = ch[i].first;
		
		adj += (pre != nxt);
		if(L){
			if(pre == nxt){
				len[pre].emplace_back(L);
			}
			else{
				len[pre+nxt+2].emplace_back(L);
			}
		}
	}
	for(int i=0;i<6;i++) sort(len[i].begin(), len[i].end());
	
	for(int i=0;i<6;i++){
		rui[i].assign(len[i].size()+1, 0);
		for(int j=0;j<(int)len[i].size();j++){
			rui[i][j+1] = rui[i][j] + len[i][j];
		}
	}
	for(int i=3;i<6;i++){
		for(int j=0;j+1<(int)len[i].size();j+=2){
			two[i-3][0].emplace_back(len[i][j] + len[i][j+1]);
		}
		for(int j=1;j+1<(int)len[i].size();j+=2){
			two[i-3][1].emplace_back(len[i][j] + len[i][j+1]);
		}
	}
	
	for(int t=0;t<3;t++){
		subset_dp[t].assign(n+1, -1);
		int sz = (int)len[t].size();
		subset_dp[t][0] = sz;
		
		if(sz == 0) continue;
		
		vector<pair<int,int>>compress;
		int pre = len[t][sz-1], cnt = 1;
		for(int i=sz-2;i>=-1;i--){
			if(i == -1 or pre != len[t][i]){
				compress.emplace_back(pre, cnt);
				if(i == -1) break;
				else{
					pre = len[t][i], cnt = 1;
				}
			}
			else cnt ++;
		}
		
		B cur; cur.reset();
		cur[0] = 1;
		constexpr int thres = 10;
		int nxt_pos = sz;
		for(auto [e,cnt]:compress){
			if(cnt >= thres){
				for(int i=0;i<e;i++){
					int max_good = -1;
					vector<pair<int,int>>upd;
					
					for(int j=i;j<=n;j+=e){
						if(cur[j]){
							max_good = j;
						}
						else{
							if(max_good >= 0 and max_good >= j-cnt*e){
								int dp = nxt_pos - (j-max_good) / e;
								upd.emplace_back(j, dp);
							}
						}
					}
					for(auto [id,dp]:upd){
						subset_dp[t][id] = dp;
						cur[id] = 1;
					}
				}
			}
			else{
				for(int i=0;i<cnt;i++){
					B nxt = cur | (cur << e);
					cur ^= nxt;
					for(int j=cur._Find_first();j<cur.size();j=cur._Find_next(j)){
						subset_dp[t][j] = nxt_pos-(i+1);
					}
					swap(cur, nxt);
				}
			}
					
			nxt_pos -= cnt;
		}
		
		auto make = [&](auto self,int id,int l,int r)->void{
			if(l == r){
				subset_rmq[t][id] = subset_dp[t][l];
				return;
			}
			int m = (l+r)/2;
			self(self,id*2+1,l,m);
			self(self,id*2+2,m+1,r);
			subset_rmq[t][id] = max(subset_rmq[t][id*2+1], subset_rmq[t][id*2+2]);
			return;
		};
		subset_rmq[t].assign(4*n+5, -1);
		make(make, 0, 0, n);
	}
	auto query = [&](auto self,int t,int a,int b,int id,int l,int r)->int{
		if(a>b or r<a or b<l) return -1;
		if(a<=l and r<=b) return subset_rmq[t][id];
		int m=(l+r)/2;
		int v1 = self(self,t,a,b,id*2+1,l,m);
		int v2 = self(self,t,a,b,id*2+2,m+1,r);
		return max(v1,v2);
	};
	for(int t=0;t<3;t++){
		cnt_up_len[t].assign(n+1, 0);
		int nxt = 0;
		for(int i=0;i<=n;i++){
			while(nxt < (int)len[t].size() and len[t][nxt] == i) nxt++;
			cnt_up_len[t][i] = nxt;
		}
	}
	for(int t=0;t<3;t++){
		for(int p=0;p<2;p++){
			if(p == 1 and len[t+3].empty()) continue;
			
			cnt_up_two[t][p].assign(n+1, 0);
			int nxt = 0;
			for(int i=0;i<=n;i++){
				while(nxt < (int)two[t][p].size() and two[t][p][nxt] == i) nxt++;
				cnt_up_two[t][p][i] = nxt;
			}
		}
	}
	auto func1=[&](int t, int cnt, int l, int r){
		if(rui[t].back() == cnt){
			if(l == 0) return 0;
			else return n;
		}
		int use = upper_bound(rui[t].begin(), rui[t].end(), cnt) - rui[t].begin();
		use --;
		int rem = cnt - rui[t][use];
		
		if(query(query,t,l,min(n,r+rem),0,0,n) >= use){
			return ((int)len[t].size() - use)*2;
		}
		else{
			return ((int)len[t].size() - use)*2+1;
		}
	};
	auto func2=[&](int x, int y, int s, int t){
		int xx = rui[x].back(), yy = rui[y].back(), xy = rui[x+y+2].back();
		
		int scnt = upper_bound(rui[x].begin(), rui[x].end(), s) - rui[x].begin();
		int tcnt = upper_bound(rui[y].begin(), rui[y].end(), t) - rui[y].begin();
		scnt --; tcnt --;
		
		int ret = n;
		for(int p=0;p<2;p++){
			if(p == 1 and len[x+y+2].empty()) continue;
			int sum = s+t;
			if(p == 1 and sum-len[x+y+2][0] < 0) continue;
			
			int lb = -1, ub = n;
			while(ub-lb > 1){
				int mid = (lb+ub)/2;
				if(rui[x][min(scnt, cnt_up_len[x][mid])] + rui[y][min(tcnt, cnt_up_len[y][mid])] + rui[x+y+2][cnt_up_two[x+y-1][p][mid]*2+p] >= sum) ub = mid;
				else lb = mid;
			}
			int cur = rui[x][min(scnt, cnt_up_len[x][ub])] + rui[y][min(tcnt, cnt_up_len[y][ub])] + rui[x+y+2][cnt_up_two[x+y-1][p][ub]*2+p];
			int good = min(scnt, cnt_up_len[x][ub])*2 + min(tcnt, cnt_up_len[y][ub])*2 + cnt_up_two[x+y-1][p][ub]*2+p;
			if(cur > sum){
				int need = (cur-sum);
				good -= (need+ub-1)/ub * 2;
			}
			ret = min(ret, 2*(int)(len[x].size()+len[y].size()) + (int)len[x+y+2].size() - good);
		}
		return ret;
	};
	
	int q; cin>>q;
	while(q--){
		int x,y,z;
		cin>>x>>y>>z;
		
		bool ok = 1;
		if(rui[0].back() > x or rui[1].back() > y or rui[2].back() > z) ok = 0;
		if(rui[0].back() + rui[3].back() + rui[4].back() < x) ok = 0;
		if(rui[1].back() + rui[3].back() + rui[5].back() < y) ok = 0;
		if(rui[2].back() + rui[4].back() + rui[5].back() < z) ok = 0;
		if(ok){
			cout << adj << '\n';
			continue;
		}
		
		int ans = n;
		
		if(rui[0].back() + rui[3].back() + rui[4].back() <= x){
			if(rui[1].back()+rui[5].back() <= y){
				int zan = y - rui[1].back() - rui[5].back();
				ans = min(ans, func1(2, z, zan, zan));
			}
			else if(rui[2].back()+rui[5].back() <= z){
				int zan = z - rui[2].back() - rui[5].back();
				ans = min(ans, func1(1, y, zan, zan));
			}
			else{
				ans = min(ans, func2(1, 2, y, z));
			}
		}
		if(rui[1].back() + rui[3].back() + rui[5].back() <= y){
			if(rui[0].back()+rui[4].back() <= x){
				int zan = x - rui[0].back() - rui[4].back();
				ans = min(ans, func1(2, z, zan, zan));
			}
			else if(rui[2].back()+rui[4].back() <= z){
				int zan = z - rui[2].back() - rui[4].back();
				ans = min(ans, func1(0, x, zan, zan));
			}
			else{
				ans = min(ans, func2(0, 2, x, z));
			}
		}
		if(rui[2].back() + rui[4].back() + rui[5].back() <= z){
			if(rui[0].back()+rui[3].back() <= x){
				int zan = x - rui[0].back() - rui[3].back();
				ans = min(ans, func1(1, y, zan, zan));
			}
			else if(rui[1].back()+rui[3].back() <= y){
				int zan = y - rui[1].back() - rui[3].back();
				ans = min(ans, func1(0, x, zan, zan));
			}
			else{
				ans = min(ans, func2(0, 1, x, y));
			}
		}
		
		if(rui[0].back() > x and rui[1].back()+rui[3].back() <= y and rui[2].back()+rui[4].back() <= z){
			int remy = y - rui[1].back() - rui[3].back();
			int remz = z - rui[2].back() - rui[4].back();
			int yz = rui[5].back();
			int ymin = remy - min(remy, yz);
			int ymax = remy - (yz - min(remz, yz));
			ans = min(ans, func1(0, x, ymin, ymax));
		}
		if(rui[1].back() > y and rui[0].back()+rui[3].back() <= x and rui[2].back()+rui[5].back() <= z){
			int remx = x - rui[0].back() - rui[3].back();
			int remz = z - rui[2].back() - rui[5].back();
			int xz = rui[4].back();
			int xmin = remx - min(remx, xz);
			int xmax = remx - (xz - min(remz, xz));
			ans = min(ans, func1(1, y, xmin, xmax));
		}
		if(rui[2].back() > z and rui[0].back()+rui[4].back() <= x and rui[1].back()+rui[5].back() <= y){
			int remx = x - rui[0].back() - rui[4].back();
			int remy = y - rui[1].back() - rui[5].back();
			int xy = rui[3].back();
			int xmin = remx - min(remx, xy);
			int xmax = remx - (xy - min(remy, xy));
			ans = min(ans, func1(2, z, xmin, xmax));
		}
		
		cout << adj+ans << '\n';
	}
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...