互测3
A. End Sky II
考虑从高到低贪心的选择,如果这一位能是 \(1\) 就让他是 \(1\)
那么现在只用考虑一个 \(ans\) 能否满足条件
先单调栈求出每个数以他为最大值能到达的左右边界
然后设 \(f_i\) 表示以第 \(i\) 个为最大值之一,前 \(i\) 个最多划分成多少组
那么他能影响到的位置就是 \(i,R_i\) ,可以和前面的查询到的位置就是 \(L_i,i\)
用线段树维护最大值就行,最后看所有能到的右端点的 \(f\) 值是否大于 \(k\)
转移时要保证把他和检验的答案按位与上答案不会变小
Code
#include<bits/stdc++.h>
//#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define lson rt<<1
#define rson rt<<1|1
#define rint signed
#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,K,ans;
int a[200010],L[200010],R[200010];
int stk[200010],p;
struct seg{
int mx,atag;
}st[200010*4];
inline void pushup(int rt){st[rt].mx=max(st[lson].mx,st[rson].mx);}
inline void pushdown(int rt){
if(st[rt].atag){
st[lson].mx=max(st[lson].mx,st[rt].atag);
st[lson].atag=max(st[lson].atag,st[rt].atag);
st[rson].mx=max(st[rson].mx,st[rt].atag);
st[rson].atag=max(st[rson].atag,st[rt].atag);
st[rt].atag=0;
}
}
void build(int rt,int l,int r){
st[rt].mx=-1,st[rt].atag=0;if(l==r) return st[rt].mx=(l==0)?(0):(-1),void();
int mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
pushup(rt);
}
void upd(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),st[rt].atag=max(st[rt].atag,k),void();
int mid=(l+r)>>1;pushdown(rt);
if(L<=mid) upd(lson,l,mid,L,R,k);
if(R>mid) upd(rson,mid+1,r,L,R,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=-1;pushdown(rt);
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;
}
inline bool check(int x){
build(1,0,n);int res=0;
for(int i=1,f;i<=n;i++) if((x&a[i])>=x){
f=query(1,0,n,L[i],i);if(f!=-1) f++;
if(f!=-1) upd(1,0,n,i,R[i],f);
if(R[i]==n) res=max(res,f);
}
return res>=K;
}
namespace force{
int f[310][310],mx[310][310];
inline bool check(int x){
memset(f,0,sizeof(f));f[0][0]=1;
for(int i=1;i<=n;i++) for(int j=1;j<=K;j++) for(int k=0;k<i;k++) if(f[k][j-1]&&((mx[k+1][i]&x)>=x)) f[i][j]=1;
return f[n][K];
}
signed main(){
for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) mx[i][j]=max(mx[i][j-1],a[j]);
for(int i=30;~i;i--) if(check(ans|1<<i)) ans|=1<<i;
printf("%d\n",ans);
return 0;
}
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("sky.in","r",stdin);
freopen("sky.out","w",stdout);
n=read(),K=read();for(int i=1;i<=n;i++) a[i]=read();if(n<=300) return force::main();
for(int i=n;i;i--){while(p&&a[stk[p]]<a[i]) L[stk[p--]]=i;stk[++p]=i;}while(p) L[stk[p--]]=0;
for(int i=1;i<=n;i++){while(p&&a[stk[p]]<a[i]) R[stk[p--]]=i-1;stk[++p]=i;}while(p) R[stk[p--]]=n;
for(int i=30;~i;i--) if(check(ans|1<<i)) ans|=1<<i;
printf("%d\n",ans);
return 0;
}
B. Hill of Sunflowers
\(n\) 的范围很小于是直接去枚举所有可能的相对大小顺序,然后求出 \(lis\) 再乘上方案数
\(a_i\) 的值域很大,于是离散化下来,以每个断点最为分界线去求方案数
从小到大依次枚举每种相对大小所在的值域段,然后在同一相同的不同相对大小的取值不能相同
直接组合数乘一下
Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define mod 1000000007
#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,sum,ans;
int a[10],rk[10],f[10],iseg[10],in[10],cnt[10];
int fac[10],inv[10];
vector<int>seg,chk;
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;
}
inline int C(int n,int m){if(m>n) return 0;int res=inv[m];for(int i=n;i>n-m;i--) res=res*i%mod;return res;}
void dfs2(int x){
if(x==m+1){
for(int i=1;i<=n;i++) in[i]=iseg[rk[i]];
for(int i=1;i<=n;i++) if(seg[in[i]]>a[i]) return ;
int v=1;
for(int i=0;i<seg.size();i++) cnt[i]=0;
for(int i=1;i<=m;i++) cnt[iseg[i]]++;
for(int i=0;i<seg.size();i++) (v*=C(seg[i]-((i==0)?(0):(seg[i-1])),cnt[i]))%=mod;
return (sum+=v)%=mod,void();
}
for(int i=iseg[x-1];i<seg.size();i++){iseg[x]=i;dfs2(x+1);}
}
void dfs1(int x){
if(x==n+1){
chk.clear();
for(int i=1;i<=n;i++) chk.emplace_back(rk[i]);
sort(chk.begin(),chk.end());
chk.resize(unique(chk.begin(),chk.end())-chk.begin());
if(chk.back()!=chk.size()) return ;m=chk.size();
for(int i=1;i<=n;i++) f[i]=1;
for(int i=1;i<=n;i++) for(int j=1;j<i;j++) if(rk[j]<rk[i]) f[i]=max(f[i],f[j]+1);
int v=0;for(int i=1;i<=n;i++) v=max(v,f[i]);
dfs2(1);(ans+=v*sum)%=mod;sum=0;
return ;
}
for(int i=1;i<=n;i++){rk[x]=i;dfs1(x+1);}
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("hill.in","r",stdin);
freopen("hill.out","w",stdout);
fac[0]=inv[0]=1;for(int i=1;i<=6;i++) fac[i]=fac[i-1]*i%mod,inv[i]=inv[i-1]*qpow(i,mod-2)%mod;
n=read();for(int i=1;i<=n;i++) seg.emplace_back(a[i]=read());
sort(seg.begin(),seg.end());
seg.resize(unique(seg.begin(),seg.end())-seg.begin());
dfs1(1);for(int i=1;i<=n;i++) ans=ans*qpow(a[i],mod-2)%mod;
printf("%lld\n",ans);
return 0;
}
C. Wonderful Everyday
假设 \(a+b=c\) 其中 \(a\) 是较大的数
那么若 \(|a|=m-1\) 那么 \(|b|=m-1\)
若 \(|a|=m\) 那么 \(|b|=m-lcp\) 或\(|b|=m-lcp-1\)
于是就只有 \(O(n)\) 种不同的答案,直接哈希判断就行
Code
#include<bits/stdc++.h>
//#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define uint unsigned long long
#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;
uint hs[500010],ht[500010],pw[500010];
char s[500010],t[500010];
inline uint geths(int l,int r){return hs[r]-hs[l-1]*pw[r-l+1];}
inline uint getht(int l,int r){return ht[r]-ht[l-1]*pw[r-l+1];}
inline int getlcp(int L){
int l=1,r=m,res=0;
while(l<=r){
int mid=(l+r)>>1;
if(geths(L,L+mid-1)==getht(1,mid)) l=mid+1,res=mid;
else r=mid-1;
}
return res;
}
namespace jud1{
#define mod 1004535809
int sum[500010],pw[500010],ans;
inline void pre(){
for(int i=1;i<=m;i++) t[i]=t[i]-'0';for(int i=1;i<=n;i++) s[i]=s[i]-'0';
pw[0]=1;for(int i=1;i<=n;i++) sum[i]=(1ll*sum[i-1]*10+s[i])%mod,pw[i]=1ll*pw[i-1]*10%mod;
for(int i=1;i<=m;i++) ans=(1ll*ans*10+t[i])%mod;
}
inline bool check(int l1,int r1,int l2,int r2){
if(l1>r1||l2>r2) return false;
int v1,v2;
v1=(sum[r1]-1ll*sum[l1-1]*pw[r1-l1+1]%mod+mod)%mod;
v2=(sum[r2]-1ll*sum[l2-1]*pw[r2-l2+1]%mod+mod)%mod;
return (v1+v2)%mod==ans;
}
#undef mod
}
namespace jud2{
#define mod 998244853
int sum[500010],pw[500010],ans;
inline void pre(){
//for(int i=1;i<=m;i++) t[i]=t[i]-'0';for(int i=1;i<=n;i++) s[i]=s[i]-'0';
pw[0]=1;for(int i=1;i<=n;i++) sum[i]=(1ll*sum[i-1]*10+s[i])%mod,pw[i]=1ll*pw[i-1]*10%mod;
for(int i=1;i<=m;i++) ans=(1ll*ans*10+t[i])%mod;
}
inline bool check(int l1,int r1,int l2,int r2){
if(l1>r1||l2>r2) return false;
int v1,v2;
v1=(sum[r1]-1ll*sum[l1-1]*pw[r1-l1+1]%mod+mod)%mod;
v2=(sum[r2]-1ll*sum[l2-1]*pw[r2-l2+1]%mod+mod)%mod;
return (v1+v2)%mod==ans;
}
#undef mod
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("wonderful.in","r",stdin);
freopen("wonderful.out","w",stdout);
scanf("%s%s",s+1,t+1);n=strlen(s+1);m=strlen(t+1);
pw[0]=1;for(int i=1;i<=n;i++) pw[i]=pw[i-1]*131;
for(int i=1;i<=n;i++) hs[i]=hs[i-1]*131+s[i]-'0'+1;
for(int i=1;i<=m;i++) ht[i]=ht[i-1]*131+t[i]-'0'+1;
jud1::pre();jud2::pre();
for(int i=1,l1,r1,l2,r2,L;i<=n;i++){
if(i>=m-1){
r1=i ;l1=r1-(m-1)+1;
l2=i+1;r2=l2+(m-1)-1;
if(jud1::check(l1,r1,l2,r2)&&jud2::check(l1,r1,l2,r2)) printf("%d %d\n%d %d\n",l1,r1,l2,r2),exit(0);
}
if(i>=m){
r1=i ;l1=r1-m+1;L=m-getlcp(l1);
l2=i+1;r2=l2+L-1;
if(jud1::check(l1,r1,l2,r2)&&jud2::check(l1,r1,l2,r2)) printf("%d %d\n%d %d\n",l1,r1,l2,r2),exit(0);
l2=i+1;r2=l2+L-1-1;
if(jud1::check(l1,r1,l2,r2)&&jud2::check(l1,r1,l2,r2)) printf("%d %d\n%d %d\n",l1,r1,l2,r2),exit(0);
}
}
for(int i=n,l1,r1,l2,r2,L;i;i--){
if(n-i+1>=m-1){
l1=i ;r1=l1+(m-1)-1;
r2=i-1;l2=r2-(m-1)+1;
if(jud1::check(l1,r1,l2,r2)&&jud2::check(l1,r1,l2,r2)) printf("%d %d\n%d %d\n",l2,r2,l1,r1),exit(0);
}
if(n-i+1>=m){
l1=i ;r1=l1+m-1;L=m-getlcp(l1);
r2=i-1;l2=r2-L+1;
if(jud1::check(l1,r1,l2,r2)&&jud2::check(l1,r1,l2,r2)) printf("%d %d\n%d %d\n",l2,r2,l1,r1),exit(0);
r2=i-1;l2=r2-L+1+1;
if(jud1::check(l1,r1,l2,r2)&&jud2::check(l1,r1,l2,r2)) printf("%d %d\n%d %d\n",l2,r2,l1,r1),exit(0);
}
}
return 0;
}