省选模拟8

A. 合成小丹

从高到低按位考虑每一位,能填 \(0\) 就填否则填 \(1\)

开一个 \(b\) 数组记录下来如果把第 \(i\) 位填 \(0\)

那么第 \(j\) 个数会与已经选择的答案不一样的位置

那么选他需要移动的位数就是最低位的 \(0\) 所在的位置

记每一个数移动的位数位 \(d_i\) 那么 \(\sum\limits_{i=1}^n\frac{1}{2^{d_i}}\) 需要大于等于 \(1\) 才能有解

如果无解,那么就加上答案

Code
#include<bits/stdc++.h>
#define int long long
#define rint signed
#define lowbit(x) x&-x
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int T,n,w,ans;
int a[100010],b[100010],t[100010];
inline bool check(){
	double res=0.0;
	for(int i=1,x;i<=n;i++){
		x=b[i]+1;x=lowbit(x);
		res+=1.0/x;
	}
	return res<1.0;
}
inline void solve(){
	n=read(),w=read();ans=0;
	for(int i=1;i<=n;i++) a[i]=read(),b[i]=0;
	for(int i=w;~i;i--){
		for(int j=1;j<=n;j++) t[j]=b[j],b[j]|=(a[j]>>i);
		if(check()){
			ans+=1ll<<i;
			for(int j=1;j<=n;j++) b[j]=t[j];
		}
	}
	printf("%lld\n",ans);
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("merge.in","r",stdin);
	freopen("merge.out","w",stdout);
	T=read();while(T--) solve();
	return 0;
}

B. 路过中丹

不难发现若有长度为 \(3\) 的回文串则直接合法

否则若能用偶回文串覆盖也合法

转化一下就变成了对于每个区间内的字符都有一个可以跟他配对

那么分别找到左右和他配对的位置记为 \(l,r\)

那么只有询问区间的端点在 \([1,l],[i,n]\)\([1,i],[r,n]\) 时才有贡献

扫描线维护一下就行

Code
#include<bits/stdc++.h>
#define int long long
#define lson rt<<1
#define rson rt<<1|1
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,q,p;
int d[2000010];
int lst[1000010];
bool ans[1000010];
char a[1000010],s[2000010];
vector<int> L[1000010],R[1000010];
struct QUE{
	int l,r,id;
	inline bool operator<(const QUE &b)const{return r<b.r;}
}QQQ[1000010];
inline void manacher(){
	for(int i=1,r=-1,mid=0;i<=p;i++){
		if(i<=r) d[i]=min(d[(mid<<1)-i],r-i+1);
		while(s[i-d[i]]==s[i+d[i]]) d[i]++;
		if(i+d[i]>r) r=d[i]+i-1,mid=i;
	}
}
namespace PRE{
	struct Seg{int mn,mx;}st[1000010*4];
	void build(int rt,int l,int r){
		st[rt].mn=inf,st[rt].mx=0;
		if(l==r) return ;
		int mid=(l+r)>>1;
		build(lson,l,mid);
		build(rson,mid+1,r);
	}
	void upd1(int rt,int l,int r,int L,int R,int k){
		if(L<=l&&r<=R) return st[rt].mn=min(st[rt].mn,k),void();
		int mid=(l+r)>>1;
		if(L<=mid) upd1(lson,l,mid,L,R,k);
		if(R>mid) upd1(rson,mid+1,r,L,R,k);
	}
	void upd2(int rt,int l,int r,int L,int R,int k){
		if(L<=l&&r<=R) return st[rt].mx=max(st[rt].mx,k),void();
		int mid=(l+r)>>1;
		if(L<=mid) upd2(lson,l,mid,L,R,k);
		if(R>mid) upd2(rson,mid+1,r,L,R,k);
	}
	pair<int,int> query(int rt,int l,int r,int pos){
		if(l==r) return make_pair(st[rt].mn,st[rt].mx);
		int mid=(l+r)>>1;pair<int,int> res=make_pair(st[rt].mn,st[rt].mx),t;
		if(pos<=mid) t=query(lson,l,mid,pos);
		else t=query(rson,mid+1,r,pos);
		res.first=min(res.first,t.first);
		res.second=max(res.second,t.second);
		return res;
	}
}
namespace SEG{
	struct Seg{int atag;}st[1000010*4];
	inline void pushdown(int rt){
		if(st[rt].atag){
			st[lson].atag+=st[rt].atag;
			st[rson].atag+=st[rt].atag;
			st[rt].atag=0;
		}
	}
	void upd(int rt,int l,int r,int L,int R){
		if(L<=l&&r<=R) return st[rt].atag++,void();
		pushdown(rt);
		int mid=(l+r)>>1;
		if(L<=mid) upd(lson,l,mid,L,R);
		if(R>mid) upd(rson,mid+1,r,L,R);
	}
	int query(int rt,int l,int r,int pos){
		if(l==r) return st[rt].atag;
		pushdown(rt);
		int mid=(l+r)>>1;
		if(pos<=mid) return query(lson,l,mid,pos);
		else return query(rson,mid+1,r,pos);
	}
}
namespace JUD{
	struct Seg{bool mrk;}st[1000010*4];
	inline void pushup(int rt){st[rt].mrk=st[lson].mrk|st[rson].mrk;}
	void build(int rt,int l,int r){
		if(l==r) return st[rt].mrk=(a[l]==a[l+2]),void();
		int mid=(l+r)>>1;
		build(lson,l,mid);
		build(rson,mid+1,r);
		pushup(rt);
	}
	bool query(int rt,int l,int r,int L,int R){
		if(L>R) return 0;
		if(L<=l&&r<=R) return st[rt].mrk;
		int mid=(l+r)>>1;bool res=0;
		if(L<=mid) res|=query(lson,l,mid,L,R);
		if(R>mid) res|=query(rson,mid+1,r,L,R);
		return res;
	}
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("pass.in","r",stdin);
	freopen("pass.out","w",stdout);
	n=read();scanf("%s",a+1);q=read();
	s[0]='~';s[1]='|';for(int i=1;i<=n;i++){s[i<<1]=a[i];s[i<<1|1]='|';}p=n<<1|1;
	manacher();PRE::build(1,1,n);JUD::build(1,1,n);
	for(int i=3,l,r,mid;i<p;i+=2){
		d[i]--;if(!d[i]) continue;d[i]>>=1;
		mid=(i-1)/2;l=mid-d[i]+1,r=mid+d[i];
		PRE::upd1(1,1,n,l,mid,mid);
		PRE::upd2(1,1,n,mid+1,r,mid+1);
	}
	for(int i=1;i<=n;i++){
		pair<int,int> res=PRE::query(1,1,n,i);
		if(res.second!=0){
			L[i].emplace_back(res.second-i+res.second-1),lst[i]=res.second-i+res.second-1;
		}
		if(res.first!=inf){
			R[res.first+res.first-i+1].emplace_back(i);
		}
	}
	for(int i=1;i<=q;i++) QQQ[i].l=read(),QQQ[i].r=read(),QQQ[i].id=i;
	sort(QQQ+1,QQQ+1+q);
	for(int i=1,now=0;i<=q;i++){
		while(now<QQQ[i].r){
			now++;
			for(auto x:L[now]) SEG::upd(1,1,n,1,x);
			for(auto x:R[now]) SEG::upd(1,1,n,lst[x]+1,x);
		}
		ans[QQQ[i].id]=((QQQ[i].r-QQQ[i].l+1)==(SEG::query(1,1,n,QQQ[i].l)))|(JUD::query(1,1,n,QQQ[i].l,QQQ[i].r-2));
	}
	for(int i=1;i<=q;i++) putchar(ans[i]+'0');
	return 0;
}

C. 膜拜大丹

显然只能选二元环

把左右两边的点分别看成 \((i,a_i),(b_j,j)\) 然后发现只有左上和右下的点能配对

扫描线从右到左扫一遍就先,每次条最靠近 \(a_i\) 的配对

Code
#include<bits/stdc++.h>
#define int long long
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,m,ans;
int a[500010],b[500010],c[500010],d[500010];
vector<int>vec[500010];
set<int>S;
set<int>::iterator iter;
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("worship.in","r",stdin);
	freopen("worship.out","w",stdout);
	n=read(),m=read();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=m;i++) vec[b[i]=read()].emplace_back(i);
	for(int i=1;i<=n;i++) c[i]=read();
	for(int i=1;i<=m;i++) d[i]=read();
	for(int i=n,res;i;i--){
		for(auto L:vec[i]) S.insert(L);
		while(!S.empty()){
			iter=S.upper_bound(a[i]);if(iter==S.begin()) break;
			iter--;
			res=min(c[i],d[*iter]);
			ans+=res;c[i]-=res,d[*iter]-=res;
			if(!d[*iter]) S.erase(iter);
			if(!c[i]) break;
		}
	}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2022-01-23 21:43  Max_QAQ  阅读(136)  评论(1编辑  收藏  举报