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;
}

浙公网安备 33010602011771号