Loading

noip模拟74

A. 自然数

线段树二分在之前的题目中出现过,但是我是用别的方法写的.

所以这个题在我这里就死了.

固定左端点应该是能想到的,因为这样的套路很多,但是自己没想到,不应该.

A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
	#define ll long long 
	#define ull unsigned ll
	#define lf long double
	#define lbt(x) (x&(-x))
	#define mp(x,y) make_pair(x,y)
	#define lb lower_bound 
	#define ub upper_bound
	#define Fill(x,y) memset(x,y,sizeof x)
	#define Copy(x,y) memcpy(x,y,sizeof x)
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	inline ll read() {
		ll w=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0; 
		while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
		return cit?w:-w;
	}
} using namespace BSS;

#define ls (x<<1)
#define rs (x<<1|1)
const ll N=1e6+21,W=2e5+21;

ll m,n,ans;
ll vis[N],val[N],lst[N],nxt[N];
struct I { ll sum,lzy,maxw; } tr[N<<2];
auto getval=[](ll 
x,ll w,ll l,ll r){ 
	tr[x].sum=(r-l+1)*w,tr[x].lzy=w,tr[x].maxw=w;
};
auto spread=[](ll x,ll l,ll r){
	ll &lzy=tr[x].lzy,mid=(l+r)>>1;
	if(~lzy) getval(ls,lzy,l,mid),getval(rs,lzy,mid+1,r),lzy=-1;
};
auto pushup=[](ll x){ 
	tr[x].sum=tr[ls].sum+tr[rs].sum;
	tr[x].maxw=max(tr[ls].maxw,tr[rs].maxw); 
};
void change(ll x,ll l,ll r,ll ql,ll qr,ll w){
	if(l>=ql and r<=qr) return getval(x,w,l,r),void();
	ll mid=(l+r)>>1; spread(x,l,r);
	if(ql<=mid) change(ls,l,mid,ql,qr,w);
	if(qr>mid) change(rs,mid+1,r,ql,qr,w);
	pushup(x);
}
ll qsum(ll x,ll l,ll r,ll ql,ll qr){
	if(l>=ql and r<=qr) return tr[x].sum;
	ll mid=(l+r)>>1,res=0; spread(x,l,r);
	if(ql<=mid) res+=qsum(ls,l,mid,ql,qr);
	if(qr>mid) res+=qsum(rs,mid+1,r,ql,qr);
	pushup(x); return res;
}
ll qmax(ll x,ll l,ll r,ll ql,ll qr){
	if(ql>qr) return -1;
	if(l>=ql and r<=qr) return tr[x].maxw;
	ll mid=(l+r)>>1,res=0; spread(x,l,r);
	if(ql<=mid) res=max(res,qmax(ls,l,mid,ql,qr));
	if(qr>mid) res=max(res,qmax(rs,mid+1,r,ql,qr));
	pushup(x); return res;
}
ll qpos(ll x,ll l,ll r,ll ql,ll qr,ll w){
	if(l==r) return tr[x].maxw>=w ? l : -1;
	ll mid=(l+r)>>1,res; spread(x,l,r);
	if(l>=ql and r<=qr){
		if(tr[ls].maxw>=w) res=qpos(ls,l,mid,ql,qr,w);
		else res=qpos(rs,mid+1,r,ql,qr,w);
		pushup(x); return res;
	}
	if(ql<=mid and tr[ls].maxw>w) res=qpos(ls,l,mid,ql,qr,w);
	else res=qpos(rs,mid+1,r,ql,qr,w);
	pushup(x); return res;
}
void build(ll x,ll l,ll r){
	tr[x].lzy=-1;
	if(l==r) return ; ll mid=(l+r)>>1;
	build(ls,l,mid),build(rs,mid+1,r);
}
signed main(){
	File(mex);
	n=read();  ll now=0,x,y;
	for(ll i=1;i<=n;i++) val[i]=read();
	for(ll i=1;i<=n;i++){
		if(val[i]>n) { change(1,1,n,i,i,now); continue; }
		if(vis[val[i]]) lst[i]=vis[val[i]],nxt[vis[val[i]]]=i; 
		vis[val[i]]=i; while(vis[now]) now++; change(1,1,n,i,i,now);
	}
	for(ll i=n;i>=1;i--){
		if(val[i]>n) continue;
		if(!nxt[i]) nxt[i]=n+1;
	}
	for(ll i=1;i<=n;i++){
		ans+=qsum(1,1,n,i,n);
		if(val[i]>n or qmax(1,1,n,i+1,n)<val[i]) continue;
		now=qpos(1,1,n,i+1,n,val[i]);
		if(now>0) change(1,1,n,now,nxt[i]-1,val[i]);
	}
	printf("%lld\n",ans),exit(0);
}

B. 钱仓

签到题,贪心乱写.

由于博主比较智障,直接糊了个线段树.

B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
	#define ll long long 
	#define ull unsigned ll
	#define lf long double
	#define lbt(x) (x&(-x))
	#define mp(x,y) make_pair(x,y)
	#define lb lower_bound 
	#define ub upper_bound
	#define Fill(x,y) memset(x,y,sizeof x)
	#define Copy(x,y) memcpy(x,y,sizeof x)
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	inline ll read() {
		ll w=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0; 
		while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
		return cit?w:-w;
	}
} using namespace BSS;

#define ls x<<1
#define rs x<<1|1
const ll N=2e5+21,inf=1e15;

ll m,n,pc,ans,minpos,minval;
ll o[N];
struct I { ll w,c,len,lc,llen; } tr[N<<2];
auto getval=[](ll x,ll c,ll len)->void{
	tr[x].c+=c,tr[x].len+=len,tr[x].w=tr[x].len-tr[x].c;
	tr[x].lc+=c,tr[x].llen+=len;
};
void update(ll x,ll l,ll r,ll ql,ll qr,ll c,ll len){
	if(l>=ql and r<=qr) return getval(x,c,len)/*,cout<<l<<' '<<r<<" "<<tr[x].c<<' '<<tr[x].w<<endl*/,void();
	 // 让 len-c 时刻都 >= 0 ,所以维护最小值,如果存在最小值小于 0,那么不行.
	ll mid=(l+r)>>1; 
	getval(ls,tr[x].lc,tr[x].llen),getval(rs,tr[x].lc,tr[x].llen);
	tr[x].lc=0,tr[x].llen=0;
	if(ql<=mid) update(ls,l,mid,ql,qr,c,len);
	if(qr>mid) update(rs,mid+1,r,ql,qr,c,len);
	ll y= (tr[ls].w<tr[rs].w ? ls : rs);
	tr[x].w=tr[y].w,tr[x].c=tr[y].c,tr[x].len=tr[y].len;
	// cout<<l<<' '<<r<<' '<<tr[x].w<<' '<<tr[ls].w<<' '<<tr[rs].w<<endl;
}
signed main(){
	File(barn);
	n=read(),m=n<<1,minval=inf; ll flag=0,res;
	for(ll i=1;i<=n;i++){
		o[i]=read(),o[i+n]=o[i],flag|=(o[i]==0);
	}
	for(ll i=m;i>=n+1;i--) pc+=o[i],update(1,1,m,i,i,pc,m-i+1);
	for(ll i=1;i<=n;i++) update(1,1,m,i,i,-inf,inf);
	if(!flag) puts("0"),exit(0); minval=tr[1].w,minpos=m;
	for(ll i=n;i>=2;i--){
		update(1,1,m,i+n,i+n,-inf,inf);
		ll r=i+n-1,l=i-1;
		update(1,1,m,l,r,-o[r+1],-1),update(1,1,m,i,i,pc,n);
		if(tr[1].w>minval) minval=tr[1].w,minpos=i+n-1;
	}
	// cout<<minval<<' '<<minpos<<endl;
	for(ll i=minpos,j=minpos;i>=minpos-n+1;i--){
		if(!o[i]){
			while(!o[j]) j--;
			o[i]++,o[j]--,ans+=(i-j)*(i-j);
		}
		else j=min(j,i-1);
	}
	printf("%lld\n",ans),exit(0);
}

C. 游戏

很明显应该是 \(dp\),很明显又应该是矩阵优化.

其实列个式子好像就很容易出来了,感觉并不是那种完全做不出来的题目。

C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
	#define ll long long 
	#define ull unsigned ll
	#define lf long double
	#define lbt(x) (x&(-x))
	#define mp(x,y) make_pair(x,y)
	#define lb lower_bound 
	#define ub upper_bound
	#define Fill(x,y) memset(x,y,sizeof x)
	#define Copy(x,y) memcpy(x,y,sizeof x)
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	inline ll read() {
		ll w=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0; 
		while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
		return cit?w:-w;
	}
} using namespace BSS;

const ll mod=1e9+7;

ll n,p,q,m,Ts;
ll f[3],g[3][3],g1[3][3],g2[3][3];
auto ksm=[](ll a,ll b,ll c)->ll{
	ll res=1; a%=c;
	for(;b;b>>=1,a=a*a%c) if(b&1) res=res*a%c;
	return res%c;
};
inline void mul(){
	ll c[3]={0};
	for(ll j=1;j<=2;j++){
		for(ll k=1;k<=2;k++)
			c[j]=(c[j]+f[k]*g[k][j]%mod)%mod;
	}
	Copy(f,c);
}
inline void mulself(){
	ll c[3][3]={0};
	for(ll i=1;i<=2;i++){
		for(ll j=1;j<=2;j++)
			for(ll k=1;k<=2;k++)
				c[i][j]=(c[i][j]+g[i][k]*g[k][j]%mod)%mod;
	}
	Copy(g,c);
}
inline void mulmore(){
	ll c[3]={0};
	for(ll j=1;j<=2;j++){
		for(ll k=1;k<=2;k++)
			c[j]=(c[j]+f[k]*g2[k][j]%mod)%mod;
	}
	Copy(f,c);
}
signed main(){
	File(game);
	Ts=read();
	while(Ts--){
		Fill(f,0),Fill(g,0);
		ll x=ksm(1e8,mod-2,mod); f[2]=1;
		n=read(),p=read()%mod*x%mod,q=read()%mod*x%mod;
		x=ksm(1-p*q%mod+mod,mod-2,mod);
		g1[1][1]=p*(1-q+mod)%mod*x%mod,g1[2][1]=(1-p+mod)*x%mod;
		g1[1][2]=(1-q+mod)*x%mod,g1[2][2]=q*(1-p+mod)%mod*x%mod;	
		x=ksm(1-(1-p+mod)%mod*(1-q+mod)%mod+mod,mod-2,mod);
		g2[1][1]=(1-p+mod)*q%mod*x%mod,g2[2][1]=p*x%mod;
		g2[1][2]=q*x%mod,g2[2][2]=(1-q+mod)*p%mod*x%mod;
		for(ll i=1;i<=2;i++){
			for(ll j=1;j<=2;j++)
				for(ll k=1;k<=2;k++)
					g[i][j]=(g[i][j]+g2[i][k]*g1[k][j]%mod)%mod;
		}
		m=n>>1; for(;m;m>>=1,mulself()) if(m&1) mul();
		if(n&1) mulmore();
		printf("%lld\n",f[1]);
	}
	exit(0);
}

D. Sanrd

容易发现一个性质,对于每一对 \(LIS\)\(LDS\),最多都只有一个交点.

所以可以选择统计一个 \(LIS\) 中每个点出现在 \(LDS\) 的次数,来判断这个 \(LIS\) 是否合法.

关于统计次数,正着做一遍 \(BIT\) 反着做一遍 \(BIT\),然后乘法原理即可.

\(f_i\) 表示 \(i\) 这个点在 \(LDS\) 中出现的次数,\(alls\) 表示所有 \(LDS\) 的个数.

所以这个 \(LIS\) 合法的条件就是 \(\sum f_i\le alls\).

于是随便选一个 \(LIS\) 删掉,然后再做一遍 \(LDS\) 就可以了.

D_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
	#define ll long long
	#define lf double
	#define ull unsigned ll
	#define mp make_pair
	#define lb lower_bound
	#define ub upper_bound
	#define lbt(x) ((x)&(-(x)))
	#define Fill(x,y) memset(x,y,sizeof(x))
	#define Copy(x,y) memcpy(x,y,sizeof(x))
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	auto read=[]()->ll{
		ll w=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
		while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
		return cit?w:(-w);
	};
} using namespace BSS;

const ll N=5e5+21,mod=998244353,inf=1e15;

ll m,n,lis,lds,alls;
ll f[N],val[N],ans[N],vis[N],pre[N],ld[N];
pair<ll,ll> ds[N];
struct I { ll a,id,ids; ll g[2][2]; } is[N];
struct FinI {
	pair<ll,ll> res; pair<ll,ll> c[N<<1];
	inline void update(ll x,ll w,ll wc){
		for(;x<=n;x+=lbt(x)){
			if(c[x].first<w) c[x].first=w,c[x].second=0;
			(c[x].second+=wc*(w==c[x].first))%=mod;
		}
	}
	inline pair<ll,ll> query(ll x){
		res.first=0,res.second=0;
		for(;x;x&=x-1){
			if(c[x].first>res.first) res.first=c[x].first,res.second=0;
			(res.second+=c[x].second*(c[x].first==res.first))%=mod;
		}
		return res;
	}
	inline void clr(){ Fill(c,0); }
}A;
struct FinII {
	ll res; I c[N<<1];
	inline void change(I &x,I y){
		if(!y.ids) return ;
		if(x.a<y.a) x.a=y.a,x.ids=0;
		if(x.ids==2) return ;
		if(x.a==y.a){
			if(y.ids==2){
				x.g[0][0]=y.id,x.g[0][1]=y.g[0][1];
				x.g[1][0]=y.id,x.g[1][1]=y.g[1][1];
				return x.ids=2,void();
			}
			if(!x.ids){
				x.g[0][0]=y.id,x.g[0][1]=y.g[0][1];
				return x.ids=1,void();
			}
			if(y.g[0][1]==x.g[0][1]) return ;
			x.ids=2,x.g[1][0]=y.id,x.g[1][1]=y.g[0][1];
		}
	}
	inline void update(ll x,I w){
		for(;x<=n;x+=lbt(x)) change(c[x],w);
	}
	inline void query(ll u,ll v){
		I &x=is[v];
		for(I y;u;u&=u-1){
			y=c[u];
			if(!y.ids) continue;
			if(x.a<y.a) x.a=y.a,x.ids=0;
			if(x.ids==2) continue;
			if(x.a==y.a){
				if(y.ids==2){
					x.g[0][0]=y.g[0][0],x.g[0][1]=y.g[0][1];
					x.g[1][0]=y.g[1][0],x.g[1][1]=y.g[1][1];
					x.ids=2; continue;
				}
				if(!x.ids){
					x.g[0][0]=y.g[0][0],x.g[0][1]=y.g[0][1];
					x.ids=1; continue;
				}
				if(y.g[0][1]==x.g[0][1]) continue;
				x.ids=2,x.g[1][0]=y.g[0][0],x.g[1][1]=y.g[0][1];
			}
		}
	}
}B;
struct FinIII {
	ll c[N<<1];
	inline void change(ll &x,ll y){ if(ld[x]<ld[y]) x=y; }
	inline void update(ll x,ll w){ for(;x<=n;x+=lbt(x)) change(c[x],w);  }
	inline void query(ll x,ll y){ for(;x;x&=x-1) change(pre[y],c[x]); }
}C;
signed main(){
	File(sanrd);
	n=read();  pair<ll,ll> res; ll u,v,w;
	for(ll i=1;i<=n;i++) val[i]=n-read()+1,is[i].id=i;
	for(ll i=1;i<=n;i++){
		ds[i]=A.query(val[i]),ds[i].first++;
		if(ds[i].first==1) ds[i].second=1;
		lds=max(lds,ds[i].first);
		A.update(val[i],ds[i].first,ds[i].second);
	}
	A.clr(); 
	for(ll i=n;i>=1;i--){
		val[i]=n-val[i]+1,res=A.query(val[i]),res.first++;
		if(res.first==1) res.second=1;
		if(res.first+ds[i].first==lds+1) f[i]=res.second*ds[i].second%mod;
		A.update(val[i],res.first,res.second);
	}
	for(ll i=1;i<=n;i++)
		alls=(alls+ds[i].second*(ds[i].first==lds))%mod;
	for(ll i=1;i<=n;i++){
		B.query(val[i],i); I &x=is[i]; x.a++;
		if(x.a==1) x.ids=1;
		(x.g[0][1]+=f[i])%=mod,(x.g[1][1]+=f[i])%=mod;
		B.update(val[i],x),lis=max(lis,x.a);
		// cout<<lis<<' '<<is[i].a<<" "<<is[i].ids<<' '<<is[i].g[0][0]<<' '<<is[i].g[1][0]<<endl;	
	}
	u=0;
	for(ll i=1;i<=n;i++){
		if(is[i].a==lis){
			if(is[i].ids>=1 and is[i].g[0][1]!=alls){ u=i,v=is[i].g[0][0],w=is[i].g[0][1]; break; }
			if(is[i].ids==2 and is[i].g[1][1]!=alls){ u=i,v=is[i].g[1][0],w=is[i].g[1][1]; break; }
		}
	}
	if(!u) puts("-1"),exit(0);
	for(ll i=lis;i>=1;i--){
		vis[u]=1,ans[i]=u,w=(w-f[u]+mod)%mod,u=v;
		if(is[v].ids>=1 and is[v].g[0][1]==w) v=is[v].g[0][0];
		else v=is[v].g[1][0];
	}
	ll len=0; u=0;
	for(ll i=n;i>=1;i--){
		if(vis[i]) continue;
		C.query(val[i],i);
		ld[i]=ld[pre[i]]+1;len=max(len,ld[i]);
		C.update(val[i],i);
	}
	if(len!=lds) puts("-1"),exit(0);
	for(ll i=1;i<=n;i++){
		if(vis[i]) continue;
		if(ld[i]==lds){ u=i; break; }
	}
	printf("%lld\n",lis); for(ll i=1;i<=lis;i++) printf("%lld ",ans[i]); 
	printf("\n%lld\n",lds); for(ll i=1;i<=lds;i++) printf("%lld ",u),u=pre[u];
	puts(""),exit(0);
}
posted @ 2021-10-13 06:10  AaMuXiiiiii  阅读(44)  评论(0)    收藏  举报