省选模拟 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 不会太菜了。

posted @ 2024-12-23 21:44  Ishar-zdl  阅读(42)  评论(0)    收藏  举报