互测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;
}
posted @ 2022-02-22 15:38  Max_QAQ  阅读(64)  评论(0编辑  收藏  举报