省选模拟 1
A 背包问题(knapsack)
首先都扔到最优的里面,发现有的扔不了,如果要扔需要把里面的一个拿出来,发现很像反悔贪心,直接构建反悔堆 \(q_{i,j}\) 表示把 \(i\) 的扔进 \(j\) 里。
这里的扔有两种情况,比如我要把当前物品扔到 A 背包里,并把 A 背包里的一个放到 B 背包里,一种是 B 背包有空位,直接扔,一种是 B 背包没空位,需要再把 B 背包的一个扔到 C 背包里,简单分讨一下就好了。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define pii std::pair<int,int>
#define eb emplace_back
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
std::mt19937_64 myrand(std::chrono::high_resolution_clock::now().time_since_epoch().count());
inline int R(int n){return myrand()%n+1;}
inline int read(){char ch=getchar();int x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;}
inline void Min(int &x,int y){if(x>y)x=y;}
inline void Max(int &x,int y){if(x<y)x=y;}
const int N=1e5+10;
int v[4],tot,a[N][4],now[4],w[4],ans,zc[4];
int bl[N];
struct NODE{
int w[4],id,val;
inline bool operator<(const NODE &A)const{return val<A.val;}
};
std::priority_queue<NODE> q[4][4];
inline void PUSH(int *w,int na,int id){
bl[na]=id;
for(int i=1;i<=3;++i){
if(i==id)continue;
q[id][i].push({{w[0],w[1],w[2],w[3]},na,w[i]-w[id]});
}
}
signed main(){
// freopen("in.in","r",stdin);freopen("out.out","w",stdout);
std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
for(int i=1;i<=3;++i)v[i]=read(),tot+=v[i];
for(int i=1;i<=tot;++i){
for(int j=1;j<=3;++j)w[j]=read();
int mx=0;
for(int j=1;j<=3;++j){
if(now[j]<v[j]){
Max(mx,w[j]);
}else{
for(int k=1;k<=3;++k){
if(k==j)continue;
while(!q[j][k].empty()&&bl[q[j][k].top().id]!=j)q[j][k].pop();
if(q[j][k].empty())continue;
if(now[k]<v[k])Max(mx,w[j]+q[j][k].top().val);
else{
int p;for(p=1;p<=3;++p)if(p!=k&&p!=j)break;
while(!q[k][p].empty()&&bl[q[k][p].top().id]!=k)q[k][p].pop();
if(q[k][p].empty())continue;
Max(mx,w[j]+q[j][k].top().val+q[k][p].top().val);
}
}
}
}
for(int j=1;j<=3;++j){
bool pd=0;
if(now[j]<v[j]){
if(mx==w[j]){
PUSH(w,i,j);now[j]++;pd=1;break;
}
}else{
for(int k=1;k<=3;++k){
if(k==j||q[j][k].empty())continue;
if(now[k]<v[k]){
if(mx==w[j]+q[j][k].top().val){
for(int f=1;f<=3;++f)zc[f]=q[j][k].top().w[f];
PUSH(zc,q[j][k].top().id,k);now[k]++;q[j][k].pop();
PUSH(w,i,j);
pd=1;break;
}
}else{
int p;for(p=1;p<=3;++p)if(p!=k&&p!=j)break;
if(q[k][p].empty())continue;
if(mx==w[j]+q[j][k].top().val+q[k][p].top().val){
for(int f=1;f<=3;++f)zc[f]=q[j][k].top().w[f];
PUSH(zc,q[j][k].top().id,k);q[j][k].pop();
for(int f=1;f<=3;++f)zc[f]=q[k][p].top().w[f];
PUSH(zc,q[k][p].top().id,p);q[k][p].pop();now[p]++;
PUSH(w,i,j);
pd=1;break;
}
}
}
}
if(pd)break;
}
ans+=mx;
}
std::cout<<ans<<'\n';
}
B 游戏(game)
简单手玩后发现可以 \(\mathcal{O}(n)\) 暴力检查状态,轻松得到一个无脑的 \(\mathcal{O}(n^2)\),不难发现如果是奇数先手必胜,偶数才需要看后面 \(k\) 个位置,上面那个 \(\mathcal{O}(n)\) 的暴力就相当于一个跳必败的过程,处理整块的必败点跳到块内最前面的位置,散块暴力即可,预处理出来每个位置块内最前面的偶数位置即可做到拼接。
点击查看代码
#include<bits/stdc++.h>
#define fi first
#define se second
#define pii std::pair<int,int>
#define eb emplace_back
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
std::mt19937_64 myrand(std::chrono::high_resolution_clock::now().time_since_epoch().count());
inline int R(int n){return myrand()%n+1;}
inline int read(){char ch=getchar();int x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;}
inline void Min(int &x,int y){if(x>y)x=y;}
inline void Max(int &x,int y){if(x<y)x=y;}
const int N=2e5+10;
int n,K,Q,a[N],len,ID[N],tag[N],q[N*2],head,tail,la[2][N],ls[2][N],pre[2][N];
inline void pro(int id){
int l=(id-1)*len+1,r=std::min(l+len-1,n);
for(int o=0;o<=1;++o){
for(int i=l;i<=r;++i)a[i]^=o;
int wc=l-1;
for(int i=l;i<=r;++i){if(!a[i])wc=i;pre[o][i]=wc;}
head=1,tail=0;
for(int i=l;i<=r;++i){
la[o][i]=ls[o][i]=0;
if(!a[i]){
q[++tail]=i;
while(head<tail&&i-q[head+1]>K)++head;
if(i-q[head]>K){
la[o][i]=q[head];
ls[o][i]=ls[o][la[o][i]];
}else ls[o][i]=i;
}
}
}
for(int i=l;i<=r;++i)a[i]^=1;
}
inline void change(int l,int r){
int lid=ID[l],rid=ID[r];
if(lid==rid){
for(int i=l;i<=r;++i)a[i]^=1;
pro(lid);return;
}
for(int i=lid+1;i<rid;++i)tag[i]^=1;
for(int i=l;ID[i]==lid;++i)a[i]^=1;
for(int i=r;ID[i]==rid;--i)a[i]^=1;
pro(lid),pro(rid);
}
inline int find(int r){
if(!r)return 0;
while(ID[pre[tag[ID[r]]][r]]!=ID[r])r=pre[tag[ID[r]]][r];return pre[tag[ID[r]]][r];
}
inline int search(int x){
int l=std::max(0,x-K-1);
return find(l);
}
inline int last(int p){return ls[tag[ID[p]]][p];}
inline bool query(int l,int r){
int lid=ID[l],rid=ID[r];
if(a[l]^tag[lid])return 1;
if(lid==rid){
int p=find(r);
while(p>=l){
if(p==l)return 0;
p=la[tag[lid]][p];
}
return 1;
}
int p=find(r);
if(p==l)return 0;
if(ID[p]>lid)p=last(p);
for(;ID[p]>lid;p=search(p))p=last(p);
for(;p>=l;p=la[tag[ID[p]]][p])if(p==l)return 0;
return 1;
}
signed main(){
// freopen("in.in","r",stdin);freopen("out.out","w",stdout);
std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
n=read();K=read();Q=read();len=300;
for(int i=1;i<=n;++i)a[i]=read()&1,ID[i]=(i-1)/len+1;
for(int i=1;i<=n;i+=len)pro(ID[i]);
for(int i=1;i<=Q;++i){
int op=read(),l=read(),r=read();
if(op==1){if(read()&1)change(l,r);}
else std::cout<<(query(l,r)?"Alice":"Bob")<<'\n';
}
}
C 网格(grid)
不会,交了 std。
总结
T2 不会太菜了。

浙公网安备 33010602011771号