省选模拟19
A. 排队
做两遍 \(lis\) ,分别从前后开始
看看 \(i\) 是否在 \(lis\) 上以及这个权值是否唯一
Code
#include<bits/stdc++.h>
//#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define lowbit(x) x&-x
#define inf 0x3f3f3f3f
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,ans,a[100010];
int f1[100010],f2[100010],ct[100010];
int BIT1[100010],BIT2[100010];
inline void ins1(int x,int k){for(;x;x-=lowbit(x)) BIT1[x]=max(BIT1[x],k);}
inline int query1(int x){int res=0;for(;x<=n;x+=lowbit(x)) res=max(res,BIT1[x]);return res;}
inline void ins2(int x,int k){for(;x<=n;x+=lowbit(x)) BIT2[x]=max(BIT2[x],k);}
inline int query2(int x){int res=0;for(;x;x-=lowbit(x)) res=max(res,BIT2[x]);return res;}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("queue.in","r",stdin);
freopen("queue.out","w",stdout);
n=read();for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++){f1[i]=query2(a[i])+1;ins2(a[i],f1[i]);}
for(int i=n;i>=1;i--){f2[i]=query1(a[i])+1;ins1(a[i],f2[i]);}
for(int i=1;i<=n;i++) ans=max(ans,f1[i]);
for(int i=1;i<=n;i++) if(f1[i]+f2[i]-1==ans) ct[f1[i]]++;
printf("%d\n",ans);for(int i=1;i<=n;i++) if(f1[i]+f2[i]-1==ans&&ct[f1[i]]==1) printf("%d ",i);
return 0;
}
B. 树论
\(30\) 暴力算法是设 \(f_{x,i}\) 表示 \(x\) 选 \(i\) 时的方案数 ( \(V\) 为值域范围)
\(f_{x,i}=f_{x,i}\times \sum\limits_{j=1}^Vf_j[gcd(i,j)==1]\)
合并到根的时候对答案贡献
反演一下变成
\(\sum\limits_{j=1}^Vf_j\sum\limits_{d|i,d|j}\mu(d)\)
\(\sum\limits_{d|i}\mu(d)\sum\limits_{d|j}f_j\)
枚举倍数贡献
然后再换一下根就好了
Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define mod 1000000007
#define inf 0x3f3f3f3f
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,rt;
int l[60],r[60];
int f[60][50010],g[50010],h[50010],hh[50010],ans[60];
int head[60],ver[110],to[110],tot;
int prime[50010],mu[50010],cnt;
bool is[50010];
int gcd(int x,int y){return (!y)?(x):(gcd(y,x%y));}
inline void add(int x,int y){ver[++tot]=y;to[tot]=head[x];head[x]=tot;}
inline void md(int &x){x=(x>=mod)?x-mod:x;}
inline int qpow(int x,int k){
int res=1,base=x;
while(k){if(k&1) res=res*base%mod;base=base*base%mod;k>>=1;}
return res;
}
void dfs1(int x,int fa){
for(int i=l[x];i<=r[x];i++) f[x][i]=1;
for(int i=head[x];i;i=to[i]){
int y=ver[i];if(y==fa) continue;dfs1(y,x);
for(int i=1;i<=50000;i++) g[i]=h[i]=0;
for(int i=1;i<=50000;i++) for(int j=i;j<=50000&&j<=r[y];j+=i) md(g[i]+=f[y][j]);
for(int i=1;i<=50000;i++) if(g[i]&&mu[i]) for(int j=i;j<=50000;j+=i) (h[j]+=mu[i]*g[i])%=mod;
for(int i=l[x];i<=r[x];i++) f[x][i]=f[x][i]*h[i]%mod;
}
}
void dfs2(int x,int fa){
for(int v1=l[x];v1<=r[x];v1++) (ans[x]+=v1*f[x][v1])%=mod;
for(int i=head[x];i;i=to[i]){
int y=ver[i];if(y==fa) continue;
for(int i=1;i<=50000;i++) g[i]=h[i]=0;
for(int i=1;i<=50000;i++) for(int j=i;j<=50000&&j<=r[y];j+=i) md(g[i]+=f[y][j]);
for(int i=1;i<=50000;i++) if(g[i]&&mu[i]) for(int j=i;j<=50000;j+=i) (h[j]+=mu[i]*g[i])%=mod;
for(int i=1;i<=50000;i++) md(h[i]+=mod);
for(int i=l[x];i<=r[x];i++) f[x][i]=f[x][i]*qpow(h[i],mod-2)%mod,hh[i]=h[i];
for(int i=1;i<=50000;i++) g[i]=h[i]=0;
for(int i=1;i<=50000;i++) for(int j=i;j<=50000&&j<=r[x];j+=i) md(g[i]+=f[x][j]);
for(int i=1;i<=50000;i++) if(g[i]&&mu[i]) for(int j=i;j<=50000;j+=i) (h[j]+=mu[i]*g[i])%=mod;
for(int i=1;i<=50000;i++) md(h[i]+=mod);
for(int i=l[y];i<=r[y];i++) f[y][i]=f[y][i]*h[i]%mod;
for(int i=l[x];i<=r[x];i++) f[x][i]=f[x][i]*hh[i]%mod;
dfs2(y,x);
}
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
mu[1]=1;
for(int i=2;i<=50000;i++){
if(!is[i]) mu[i]=-1,prime[++cnt]=i;
for(int j=1;j<=cnt&&i*prime[j]<=50000;j++){
is[i*prime[j]]=1;
if(i%prime[j]==0) break;
mu[i*prime[j]]=-mu[i];
}
}
n=read();
for(int i=1;i<=n;i++) l[i]=read();for(int i=1;i<=n;i++) r[i]=read();
for(int i=1,x,y;i<n;i++){x=read(),y=read();add(x,y),add(y,x);}
dfs1(1,0);dfs2(1,0);
for(int i=1;i<=n;i++) printf("%lld\n",(ans[i]+mod)%mod);
return 0;
}
C. 麻烦的杂货店
用栈来维护括号序列的匹配
用 \(vector\) 存下所有的合法左端点,每次继承匹配的左端点 \(-1\) 的位置的 \(vector\)
然后根号分治, \(vector\) 大小小于根号的每次暴力用线段树修改
大于的每次二分左端点就行
Code
#include<bits/stdc++.h>
//#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define lson rt<<1
#define rson rt<<1|1
#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;
int fa[100010],ans[4000010],r[100010];
int stk[100010],p;
struct seg{int mx;}st[100010*4];
vector<int>A,vec[100010];
vector<pair<int,int> >Q[100010];
char str[100010];
int getfa(int x){return fa[x]==x?x:fa[x]=getfa(fa[x]);}
inline void pushup(int rt){st[rt].mx=max(st[lson].mx,st[rson].mx);}
void upd(int rt,int l,int r,int pos,int k){
if(l==r) return st[rt].mx=max(st[rt].mx,k),void();
int mid=(l+r)>>1;
if(pos<=mid) upd(lson,l,mid,pos,k);
else upd(rson,mid+1,r,pos,k);
pushup(rt);
}
int query(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R) return st[rt].mx;
int mid=(l+r)>>1,res=0;
if(L<=mid) res=max(res,query(lson,l,mid,L,R));
if(R>mid) res=max(res,query(rson,mid+1,r,L,R));
return res;
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("grocery.in","r",stdin);
freopen("grocery.out","w",stdout);
n=read(),m=read();scanf("%s",str+1);
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1,l,r;i<=m;i++){l=read(),r=read();Q[r].emplace_back(make_pair(l,i));}
for(int i=1,j;i<=n;i++){
if(str[i]=='F') stk[++p]=i;
else if(p){
j=stk[p--];fa[i]=getfa(j-1);vec[fa[i]].emplace_back(j);j=fa[i];r[j]=i;
if(vec[j].size()==2000) A.emplace_back(j);
else if(vec[j].size()<2000) for(auto L:vec[j]) upd(1,1,n,L,i-L+1);
}
for(auto L:Q[i]){
ans[L.second]=query(1,1,n,L.first,i);
for(auto Y:A){
int v=lower_bound(vec[Y].begin(),vec[Y].end(),L.first)-vec[Y].begin();
if(v!=vec[Y].size()) ans[L.second]=max(ans[L.second],r[Y]-vec[Y][v]+1);
}
}
}
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}