noip模拟29

A.最长不下降子序列

有一个显然的规律:这个序列具有循环节,所以我们根据循环节统计答案即可..
考场写挂的原因:循环节不能只累计一节进行计算..
正确的计算方式:
设单独每个循环节内部所含有的最长不下降子序列的长度为\(len\)..
设在循环节已经有了很多时,每增加一个循环节,答案应该增加\(ans\)..
那么\(ans\)的求法应该是:
\(ans=\) \(len+1\)个循环节的最长不下降子序列的长度\(-\)\(len\)个循环节的最长不下降子序列的长度
然后我们发现所有的\(ans\)都等于 \(1\)
这是通过打表发现的规律,但是也并非没有道理,前面的循环节可以放弃前面的元素然后选择更大的元素..
为了方面,我们可以直接求出\(mod+1\)\(mod\)个循环节之间的差

A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
	#define p() printf("Pass")
	#define ll long long int
	#define ull unsigned ll
	#define re register ll 
	#define lf double
	#define lb lower_bound 
	#define ub upper_bound 
	#define mp(x,y) make_pair(x,y)
	#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;
	}
	inline void write(ll ss)
	{
		static int stas[35]; int topps=0;
  		if(ss<0) putchar(‘-‘),ss=-ss;
  		do{stas[++topps]=ss%10,ss/=10;}while(ss);
  		while(topps) putchar(stas[topps--]+48); puts("");
	}
} using namespace BSS;

const ll N=1320000;

ll m,n,a,b,c,mod,t,st,en,anst;
ll val[N],f[N],vis[N],tmp[N],lsh[N];
inline void Init()
{
	n=read();
	val[1]=read();
	a=read(),b=read(),c=read(),mod=read();
}
inline void Easy_Work()
{
	for(re i=2;i<=n;i++)
	{
		val[i]=((val[i-1]*val[i-1])%mod*a)%mod+(val[i-1]*b)%mod+c%mod;
		val[i]%=mod;
	}
	ll ans=0,temp;
	for(re i=1;i<=n;i++)
	{	
		temp=ub(lsh+1,lsh+1+ans,val[i])-lsh;
		if(lsh[temp]<=val[i]) lsh[++ans]=val[i];
		else lsh[temp]=val[i];
	}
	printf("%lld\n",ans);
}
inline ll Find_Single()
{
	ll cnt=0,temp;
	for(re i=1;i<=en;i++) tmp[++cnt]=val[i];
	for(re i=1;i<=t*mod;i++) tmp[++cnt]=val[i+en];
	for(re i=st,j=1;i<=n;i++,j++) tmp[++cnt]=val[j+en];
	ll ans=0;
	for(re i=1;i<=cnt;i++)
	{
		temp=ub(lsh+1,lsh+1+ans,tmp[i])-lsh;
		if(lsh[temp]<=tmp[i]) lsh[++ans]=tmp[i];
		else lsh[temp]=tmp[i];
	}
	return ans;
}
inline void Work()
{
	for(re i=2;i<=mod*mod;i++)
	{
		val[i]=((val[i-1]*val[i-1])%mod*a)%mod+(val[i-1]*b)%mod+c%mod;
		val[i]%=mod;
	}
	for(re i=1;i<=mod*mod;i++)
	{
		if(vis[val[i]])
		{
			t=i-vis[val[i]];
			en=vis[val[i]]-1;
			break;
		}
		vis[val[i]]=i;
	}
	ll temp=n-en; temp/=t; // temp即为周期个数
	st=temp*t+en+1; 
 	ll res=Find_Single();
 	temp-=mod;
 	res+=temp;
 	printf("%lld\n",res);
}
signed main()
{	
	Init();
	if(n<=mod*mod) Easy_Work();
	else Work();
//	Easy_Work();
	return 0;
}

B.完全背包问题

这道题运用了剩余系的思想,从而达到了节约时空的效果,是一个很不错的优化..
然后我们会发现其实这个题对于 \(\leq L\) 的物品可以看作一个非拓扑序的动态转移方程,所以可以建立一个超级源点,然后跑最短路即可..
时间复杂度为\(O(nm · SSSP (V + 1, 2V ))\)

但是对于另外一种方法:
我们会发现所有的环都是不交的,所以这时我们可以选择找到所有与\(S\)相连的顶点中对应边权最小的顶点\(P\),那么\(S\)\(P\)的最短路一定就是\(path(S,P)\),这是我们删掉所有与\(P\)相连的实边,这时环消失,变成了一个拓扑图..
自环直接删了就行..

B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
	#define p() printf("Pass")
	#define ll long long int
	#define ull unsigned ll
	#define re register ll 
	#define lf double
	#define lb lower_bound 
	#define ub upper_bound 
	#define mp(x,y) make_pair(x,y)
	#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;
	}
	inline void write(ll ss)
	{
		static int stas[35]; int topps=0;
  		if(ss<0) putchar(‘-‘),ss=-ss;
  		do{stas[++topps]=ss%10,ss/=10;}while(ss);
  		while(topps) putchar(stas[topps--]+48); puts("");
	}
} using namespace BSS;

const ll N=10050;

ll m,n,l,c,mod,lmt,ts,S,tot;
ll v[N],pos[N],dis[N],head[N],vis[N];
ll dp[55][35][N];
inline ll add(ll i,ll j) { return (i%mod+j%mod+mod)%mod; }
inline ll down(ll i,ll j) { return (i%mod-j%mod+mod*mod*mod)%mod; }
struct I { ll u,v,w,nxt; } e[N*6];
inline void Init()
{
	n=read(),m=read();
	for(re i=1;i<=n;i++) v[i]=read();
	sort(v+1,v+1+n); mod=v[1];
	n=unique(v+1,v+1+n)-v-1;
	l=read(),c=read();
	if(v[n]<l) lmt=n+1;
	else lmt=lb(v+1,v+1+n,l)-v;
}
inline void Add(ll u,ll v,ll w)
{
	e[++ts].u=u;
	e[ts].v=v;
	e[ts].w=w;
	e[ts].nxt=head[u];
	head[u]=ts;
}
queue<ll> que;
inline void Spfa()
{
	que.push(S); dis[S]=0;
	ll now; vis[S]=1;
	while(que.size())
	{	
		now=que.front(); que.pop();
		for(re i=head[now];i;i=e[i].nxt)
		{
		//	cout<<now<<" "<<e[i].v<<" "<<dis[now]<<" "<<e[i].w<<" "<<dis[e[i].v]<<endl;
			if(dis[e[i].v]>=dis[now]+e[i].w)
			{
				dis[e[i].v]=dis[now]+e[i].w;
				if(!vis[e[i].v]) que.push(e[i].v);
				vis[e[i].v]=1;
			}
		}
		vis[now]=0;
	}
	return ;
}
inline void Work()
{
	
	Fill(dp,0x3f); Fill(dis,0x3f);
	dp[lmt-1][0][0]=0; long long int w;
	for(re i=lmt-1;i<=n;i++)
	{
		for(re j=0;j<=c;j++)
		{
			for(re k=0;k<mod;k++)
			{
				dp[i][j+1][add(k,v[i])]=min(dp[i][j][k]+v[i],dp[i][j+1][add(k,v[i])]);
				dp[i+1][j][k]=min(dp[i+1][j][k],dp[i][j][k]);
				dp[i+1][j+1][add(k,v[i])]=min(dp[i+1][j+1][add(k,v[i])],dp[i][j][k]+v[i+1]);
			//	cout<<i<<" "<<j<<" "<<k<<" "<<dp[i][j][k]<<" \n";
			}
		}	
	}
	S=++tot;
	for(re i=0;i<mod;i++) pos[i]=++tot;
	for(re k=0;k<mod;k++)
	{
		for(re i=lmt;i<=n;i++)
		{
			for(re j=0;j<=c;j++)		
			{	
				dis[pos[k]]=min(dis[pos[k]],dp[i][j][k]);
			}
		}
		Add(S,pos[k],dis[pos[k]]);
	}
	for(re i=0;i<mod;i++)
	{
		for(re j=1;j<=lmt-1;j++)
		{
			Add(pos[i],pos[add(i,v[j])],v[j]);
		}
	}
	for(re i=1;i<=lmt-1;i++) Add(S,pos[v[i]%mod],v[i]);
	for(re i=1;i<=lmt-1;i++)
	{
		for(re j=1;j<=lmt-1;j++)
		{
			Add(pos[v[i]%mod],pos[v[j]%mod],v[j]);
		}
	}
	Spfa();
	while(m--)
	{
		scanf("%lld",&w);  //cout<<dis[pos[w%mod]]<<" "<<pos[w%mod]<<endl;
		dis[pos[w%(1ll*mod)]]<=w or (!w) ? puts("Yes") : puts("No") ;
	}
	return ;
}
signed main()
{
//	File(0.in,aout);
	Init(); Work();
	return 0;
}

C.最近公共祖先

算是比较简单的一道了..
对于这种树上的染色问题..绝大部分都是树剖或者LCT套一个线段树吧..
比较妙的一个剪枝,也是考场上唯一没有想到的地方..就是可以选择如果已经将父亲的值传给了自己的兄弟和自己的父亲..那么就不再访问这个点了..

C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
	#define p() printf("Pass")
	#define ll long long int
	#define ull unsigned ll
	#define re register ll 
	#define lf double
	#define lb lower_bound 
	#define ub upper_bound 
	#define mp(x,y) make_pair(x,y)
	#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;
	}
	inline void write(ll ss)
	{
		static int stas[35]; int topps=0;
  		if(ss<0) putchar(‘-‘),ss=-ss;
  		do{stas[++topps]=ss%10,ss/=10;}while(ss);
  		while(topps) putchar(stas[topps--]+48); puts("");
	}
} using namespace BSS;

const ll N=1e5+50;
ll m,n,tot,ts,black;
ll head[N],val[N],flag[N];
ll dep[N],fa[N],dfn[N],rk[N],son[N],top[N],siz[N];
struct I { ll u,v,nxt; } e[N*2];
struct II { ll l,r,lazy,maxn; } tr[N*20];
inline void add(ll u,ll v)
{
	e[++ts].u=u;
	e[ts].v=v;
	e[ts].nxt=head[u];
	head[u]=ts;
}
inline void Init()
{
	n=read(),m=read();
	for(re i=1;i<=n;i++) val[i]=read();
	ll u,v;
	for(re i=1;i<=n-1;i++)
	{
		u=read(),v=read();
		add(u,v); add(v,u);
	}
	return ;
}
void dfs1(ll now,ll dad,ll depth)
{
	fa[now]=dad; dep[now]=depth+1;
	siz[now]=1;
	for(re i=head[now];i;i=e[i].nxt)
	{
		if(dad==e[i].v) continue;
		dfs1(e[i].v,now,depth+1);
		siz[now]+=siz[e[i].v];
		if(siz[son[now]]<siz[e[i].v])
		{
			son[now]=e[i].v;
		}
	}
	return ;
}
void dfs2(ll now,ll high)
{
	dfn[now]=++tot; rk[tot]=now;
	top[now]=high;
	if(!son[now]) return ;
	dfs2(son[now],high);
	for(re i=head[now];i;i=e[i].nxt)
	{
		if(e[i].v==fa[now] or e[i].v==son[now]) continue;
		dfs2(e[i].v,e[i].v);
	}
	return ;
}
inline void spread(ll x)
{
	if(tr[x].lazy)
	{
		tr[x<<1].maxn=max(tr[x<<1].maxn,tr[x].lazy);
		tr[x<<1|1].maxn=max(tr[x<<1|1].maxn,tr[x].lazy);
		tr[x<<1].lazy=max(tr[x].lazy,tr[x<<1].lazy);
		tr[x<<1|1].lazy=max(tr[x].lazy,tr[x<<1|1].lazy);
		tr[x].lazy=0;
	}
	return ;
}
void build(ll x,ll l,ll r)
{
	tr[x].l=l; tr[x].r=r;
	if(tr[x].l==tr[x].r) return ;
	ll mid=(tr[x].l+tr[x].r)>>1;
	build(x<<1,l,mid); build(x<<1|1,mid+1,r);
	return ;
}
ll query(ll x,ll pos)
{
	if(tr[x].l==tr[x].r) return tr[x].maxn;
	spread(x);
	ll mid=(tr[x].l+tr[x].r)>>1;
	if(pos<=mid) return query(x<<1,pos);
	else return query(x<<1|1,pos);
}
void update(ll x,ll ql,ll qr,ll w)
{
	if(tr[x].l>=ql and tr[x].r<=qr)
	{
		tr[x].lazy=max(tr[x].lazy,w);
		tr[x].maxn=max(tr[x].maxn,w);
		return ;
	}
	spread(x);
	ll mid=(tr[x].l+tr[x].r)>>1;
	if(ql<=mid) update(x<<1,ql,qr,w);
	if(qr>=mid+1) update(x<<1|1,ql,qr,w);
}
inline void Change(ll x)
{
	update(1,dfn[x],dfn[x]+siz[x]-1,val[x]);
	// flag 记是否给自己的兄弟节点更新父亲的权值.
	ll now=x,temp;
	while(fa[now] and (!flag[now]))
	{
		temp=fa[now]; flag[now]=1;
		update(1,dfn[temp],dfn[now]-1,val[temp]);
		update(1,dfn[now]+siz[now],dfn[temp]+siz[temp]-1,val[temp]);
		now=fa[now];
	}
	return ;
}	
inline void Work()
{
	build(1,1,n);
	dfs1(1,0,1); dfs2(1,1);
	char ss[20]; ll u,v,w;
	while(m--)
	{
		scanf("%s",ss+1); u=read();
		if(ss[1]==‘Q‘)
		{
			if(!black) { puts("-1"); continue; }
			w=query(1,dfn[u]);
			printf("%lld\n",w);
		}
		if(ss[1]==‘M‘)
		{
			black=1; Change(u);
		}
	}
}
signed main()
{
	Init();
	Work();
	return 0;
}

noip模拟29

上一篇:Selenium操作CEF框架PC应用示例


下一篇:力扣-695-岛屿的最大面积