Loading

noip模拟36

A. Dove打扑克

一道很水的题,然而我考场上再次没对拍然后打挂..
忘记去重了..
此题开个桶计数就行了,树状数组优化后会飞快,不优化也能过,最大的测试点只有\(300ms+\)..

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

const ll N=1e5+51;
ll m,n,cnt,tot;
ll vis[N],with[N],w[N],rk[N],siz[N],fa[N],v[N],v2[N];
queue<ll> que;
ll find(ll x){
	return (x==fa[x]) ? x : (fa[x]=find(fa[x])) ;
}
signed main(){
	n=read(); m=read();
	ll opt,x,y,wx,wy,temp;
	vis[1]=n; with[++cnt]=1,rk[1]=cnt;
	for(re i=1;i<=n;i++) w[i]=1,fa[i]=i;
	for(re i=1;i<=m;i++){	
		opt=read(); x=read();
		if(opt&1){
			y=read(); if(find(x)==find(y)) continue;
			wx=w[find(x)],wy=w[find(y)];
			vis[wx]--,vis[wy]--;
			w[find(x)]+=wy,w[find(y)]=0;
			fa[find(y)]=find(x);
			if((!vis[wx]) and (!v[rk[wx]])){
				que.push(rk[wx]); v[rk[wx]]=1;
				with[rk[wx]]=0;
			}
			if((!vis[wy]) and (!v[rk[wy]])){
				que.push(rk[wy]); v[rk[wy]]=1;
				with[rk[wy]]=0;
			}
			if(vis[w[find(x)]]){
				vis[w[find(x)]]++;
			}
			else{
				vis[w[find(x)]]++;
				if(que.size()){
					temp=que.front();
					que.pop(); v[temp]=0;
				}
				else temp=++cnt;
				with[temp]=w[find(x)];
				rk[w[find(x)]]=temp;
			}
		}
		else{
			ll now,ans=0;
			for(re i=1;i<=cnt;i++){
				now=with[i]; if(!vis[now]) continue;
				for(re j=i;j<=cnt;j++){
					if(!vis[with[j]]) continue;
					if(abs(now-with[j])>=x){
						if(with[j]==now) ans+=vis[now]*(vis[now]-1)/2;
					 	else ans+=vis[now]*vis[with[j]];
					}
				}
			}
			printf("%lld\n",ans);
		}
	}
	return 0;
}

B. Cicada 与排序

一个大模拟上的Dp..
可以将归并排序看成异化的线段树..
\(a\)的值域大于\(n\),所以可以考虑离散化..
但是我们又发现离散化没有什么用,但是对于正解我们却发现了值域的突破口.
我们可以考虑每个单值的答案..

\(f[i][j][k]\)表示深度为\(i\),原来的位置在\(j\)后来移动到了\(k\)位置的概率..
但是发现复杂度过高,需要预先处理一些值,于是选择考虑辅助数组.
\(g[i][j]\)表示当一个指针在\(i\),另一个指针在\(j\)的概率.
关于如何转移,按照归并排序的正常流程即可..
在左区间指针和右区间指针值相同的时候,选择概率转移.
最后答案累加起来就可以了..

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

const ll N=505;
const ll mod=998244353;
ll m,n,cnt,tot,inv;
ll val[N];
ll g[N][N],dp[N][N][N];
inline ll ksm(ll a,ll b,ll c){
	ll temp=1; a%=c;
	while(b){
		if(b&1) temp=(temp*a)%c;
		a=(a*a)%c; b>>=1;
	}
	return temp%c;
}
void merge(ll dep,ll l,ll r){
	if(l==r){
		dp[dep][l][l]=1;
		return ;
	}
	ll mid=(l+r)>>1;
	merge(dep+1,l,mid); merge(dep+1,mid+1,r);
	Fill(g,0); ll len1=mid-l+1,len2=r-mid;
	g[0][0]=1;
	for(re i=0;i<=len1;i++){
		for(re j=0;j<=len2;j++){
			if(i==len1) (g[i][j+1]+=g[i][j]%mod)%=mod;
			else if(j==len2) (g[i+1][j]+=g[i][j]%mod)%=mod;
			else if(val[l+i]>val[mid+1+j]) (g[i][j+1]+=g[i][j]%mod)%=mod;
			else if(val[l+i]<val[mid+1+j]) (g[i+1][j]+=g[i][j]%mod)%=mod; 
			else{
				(g[i+1][j]+=g[i][j]*inv%mod)%=mod;
				(g[i][j+1]+=g[i][j]*inv%mod)%=mod;
			}
		}
	}
	for(re i=l;i<=r;i++){
		for(re j=0;j<=len1;j++){
			for(re k=0;k<=len2;k++){
				if(j==len1 and k==len2) continue;
				if(j==len1) (dp[dep][i][j+k+l]+=dp[dep+1][i][k+mid+1]*g[j][k]%mod)%=mod;
				else if(k==len2) (dp[dep][i][j+k+l]+=dp[dep+1][i][j+l]*g[j][k]%mod)%=mod;
				else if(val[l+j]<val[mid+1+k]) (dp[dep][i][j+k+l]+=dp[dep+1][i][j+l]*g[j][k]%mod)%=mod;
				else if(val[l+j]>val[mid+1+k]) (dp[dep][i][j+k+l]+=dp[dep+1][i][k+mid+1]*g[j][k]%mod)%=mod;
				else (dp[dep][i][j+k+l]+=(dp[dep+1][i][j+l]+dp[dep+1][i][k+mid+1])%mod*(g[j][k]*inv%mod)%mod)%=mod;
			}
		}
	}
	sort(val+l,val+r+1);
}
signed main(){
	n=read(); inv=ksm(2,mod-2,mod);
	for(re i=1;i<=n;i++) val[i]=read();
	merge(1,1,n); 
	for(re i=1;i<=n;i++){
		ll ans=0;
		for(re j=1;j<=n;j++){
			(ans+=dp[1][i][j]*j)%=mod;
		}
		printf("%lld ",ans);
	}
	return 0;
}

C. Cicada拿衣服

要透析位运算的性质,总共有\(log_2(n)\)位,所以本质不同的区间也只有\(log_2\)级别个.
然后链表维护每个区间的\(or\)\(and\)
对于\(min-max\),发现一定单调,于是在最远的合法区间二分即可.

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

const ll N=1e6+21;

ll m,n,cnt,head,tail;
ll val[N],lg2[23];
ll stmin[N][23],stmax[N][23],stor[N][23],stand[N][23];
struct I { ll l,r,pre,nxt; } e[N];
vector<ll> d[N]; multiset<ll> s;
inline void Pre(){
	n=read(),m=read();
	for(re i=1;i<=n;i++) 
		stmin[i][0]=stmax[i][0]=stor[i][0]=stand[i][0]=val[i]=read();
	for(re i=2;i<=n;i++) lg2[i]=lg2[i>>1]+1;
	for(re j=1;j<=20;j++)
		for(re i=1;i+(1<<j)-1<=n;i++){
			stmin[i][j]=min(stmin[i][j-1],stmin[i+(1<<j-1)][j-1]),
			stmax[i][j]=max(stmax[i][j-1],stmax[i+(1<<j-1)][j-1]),
			stor[i][j]=stor[i][j-1] | stor[i+(1<<j-1)][j-1],
			stand[i][j]=stand[i][j-1] & stand[i+(1<<j-1)][j-1];
		}
}
inline ll qmin(ll l,ll r){ ll Log=lg2[r-l+1]; return min(stmin[l][Log],stmin[r-(1<<Log)+1][Log]); }
inline ll qmax(ll l,ll r){ ll Log=lg2[r-l+1]; return max(stmax[l][Log],stmax[r-(1<<Log)+1][Log]); }
inline ll qor(ll l,ll r){ ll Log=lg2[r-l+1]; return stor[l][Log] | stor[r-(1<<Log)+1][Log]; }
inline ll qand(ll l,ll r){ ll Log=lg2[r-l+1]; return stand[l][Log] & stand[r-(1<<Log)+1][Log]; }
inline void update(ll i){
	e[++cnt].l=i,e[cnt].r=i,e[cnt].pre=tail,e[tail].nxt=cnt,tail=cnt;
	if(cnt==1) head=1; ll now=cnt,pre;
	while(pre=e[now].pre){
		if(qor(e[now].l,i)==qor(e[pre].l,i) and qand(e[now].l,i)==qand(e[pre].l,i)){
			e[now].l=e[pre].l,e[now].pre=e[pre].pre,e[e[pre].pre].nxt=now;
			if(!e[now].pre) head=now;
		}
		else now=e[now].pre;
	}
}
inline bool check(ll l,ll r){
	return qmin(l,r)+qor(l,r)-qmax(l,r)-qand(l,r)>=m ;
}
inline void Work(){
	ll le,ri,res,mid;
	for(re i=1;i<=n;i++){
		update(i); res=-1;
		for(re j=head;j;j=e[j].nxt){
			if(check(e[j].r,i)){
				le=e[j].l,ri=e[j].r;
				while(le<=ri){
					mid=(le+ri)>>1;
					if(check(mid,i)) res=mid,ri=mid-1;
					else le=mid+1;
				}
				break;
			}
		}
		if(res!=-1) d[res].push_back(i-res+1),d[i+1].push_back(res-i-1);
	}
	for(re i=1;i<=n;i++){
		for(auto j : d[i]){
			if(j>0) s.insert(j);
			else s.erase(s.find(-j));
		}
		if(s.size()) printf("%d ",*(--s.end()));
		else printf("-1 ");
	}
}
signed main(){
	Pre(),Work();
	exit(0);
}
posted @ 2021-08-14 21:05  AaMuXiiiiii  阅读(30)  评论(0编辑  收藏  举报