省选模拟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;
}