首页 > 其他分享 >Solution Set - 限时训练 II

Solution Set - 限时训练 II

时间:2023-06-10 14:33:26浏览次数:59  
标签:Set Matrix int Top Solution II fa le mod

HNOI2017 Day2

2023-06-10
注:Day2T2换为BJOI2017Day2T1,以匹配学习进度

HNOI2017 Day1

2023-06-09

HNOI2018 Day1

2023-05-30


A 寻宝游戏

给定\(n\)个长为\(m\)的二进制串,可以在每两个二进制数之间和第一个数之前添加一个运算符(按位与/按位或),然后在这个算式最前面填上\(0\)。问使得这个算式的值刚好为给定的询问值的添加方法数。\(q\)组询问。答案对\(10^9+7\)取模。

\(n \le 1000, m \le 5000, q \le 1000\)。


key:Adhoc

将按位与看做\(1\),按位或看做\(0\),会发现:将操作序列和每个数第\(j\)位构成的序列从后往前比较,若操作序列字典序小,则该位结果为\(1\),否则结果为\(0\)。证明是不难的。

那么只要将每一位构成的序列排序,如果询问串要求比一段前缀大,比一段后缀小就合法,输出分界点的两个数的差;否则无解。

用基数排序可以将时间复杂度做到\(O((n+q)m)\)。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1005,M=5005,mod=1e9+7;
int n,m,q,d=1,cnt[2],val[M],A[M],B[M];char s[M];
int main(){
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=m;i++)A[i]=i;
	for(int i=1;i<=n;i++,d=d*2%mod){
		scanf("%s",s+1);
		cnt[0]=0;cnt[1]=m;
		for(int j=1;j<=m;j++){
			if(s[j]=='0')cnt[0]++;
			else val[j]=(val[j]+d)%mod;
		}
		for(int j=m;j>=1;j--)
			B[cnt[s[A[j]]-'0']--]=A[j];
		for(int j=1;j<=m;j++)A[j]=B[j];
	}
	for(int i=1;i<=m;i++)B[A[i]]=i;
	A[m+1]=m+1;val[m+1]=d;
	for(int i=1;i<=q;i++){
		int L=0,R=m+1;
		scanf("%s",s+1);
		for(int j=1;j<=m;j++){
			if(s[j]=='0')L=max(L,B[j]);
			else R=min(R,B[j]);
		}
		if(L>R)printf("0\n");
		else printf("%d\n",(val[A[R]]-val[A[L]]+mod)%mod);
	}
	return 0;
}

B 转盘

一个转盘上有摆成一圈的\(n\)个物品,依次编号为\(1\sim n\),编号为的\(i\)物品会在\(T_i\)时刻出现(之后不消失)。在 \(0\) 时刻时,小G可以任选 \(n\) 个物品中的一个,每经过一个单位时间可以继续选择当前物品或选择下一个物品。在每一时刻,如果小 G 选择的物品已经出现了,那么小G将会标记它。问小G至少需要多少时间来标记所有物品。

然而还有\(m\)次修改,每次修改改变一个物品的出现时间。强制在线。

\(n,m\le 10^5\)。


建议BC两题换一下名字

key:线段树,单调栈

首先转化问题,记\(a_i=t_i-i (1 \le i \le 2n),t_{i+n}=t_i\),注意到小G最多转一圈,随便推推容易发现:以\(i\)为起点的答案是\(\max_{i\le j \lt i+n}{a_j}+n+i-1\)。然后可以把上界换成\(2n\)。

这个时候转化视角,考虑对于某个\(j\)的最小值。显然只用考虑\(a_j\)是后缀最大值的情形。设\(a_i\)是大于\(a_j\)的数中最靠右的一个,则\(a_j\)的答案是\(a_j+i+n\)。

所以可以考虑用线段树维护一个单调栈,从后向前考虑即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5,INF=1<<30;
int n,m,op,a[N<<1],ans;
struct node{int mx,res;}tr[N<<2];
int query(int p,int l,int r,int x){
	if(l==r)return tr[p].mx>x?x+l:INF;
	int mid=l+r>>1;
	if(tr[p<<1|1].mx<=x)return query(p<<1,l,mid,x);
	return min(tr[p].res,query(p<<1|1,mid+1,r,x));
}
void push_up(int p,int l,int r){
	tr[p].mx=max(tr[p<<1].mx,tr[p<<1|1].mx);
	tr[p].res=query(p<<1,l,l+r>>1,tr[p<<1|1].mx);
}
void build(int p,int l,int r){
	if(l==r){tr[p].mx=a[l]-l;return;}
	int mid=l+r>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	push_up(p,l,r);
}
void modify(int p,int l,int r,int x,int v){
	if(l==r){tr[p].mx=v-l;return;}
	int mid=l+r>>1;
	if(x<=mid)modify(p<<1,l,mid,x,v);
	else modify(p<<1|1,mid+1,r,x,v);
	push_up(p,l,r);
}
int main(){
	scanf("%d%d%d",&n,&m,&op);
	for(int i=1;i<=n;i++)scanf("%d",a+i);
	build(1,1,n);
	printf("%d\n",ans=query(1,1,n,tr[1].mx-n)+n);
	for(int i=1,x,y;i<=m;i++){
		scanf("%d%d",&x,&y);
		if(op)x^=ans,y^=ans;
		modify(1,1,n,x,y);
		printf("%d\n",ans=query(1,1,n,tr[1].mx-n)+n);
	}
	return 0;
}

C 毒瘤

\(n\)个点,\(m\)条边的连通简单无向图,求独立集个数。

\(n\le 10^5,m \le n+10\)。


key:DP,虚树/动态DP

首先随便取一棵生成树,然后标记所有非树边的端点。

对于树的情况,很容易用树形DP解决。同时有一个显然的暴力:枚举上述所有端点的颜色,做树形DP。

考虑对所有端点建出虚树,在虚树上DP。这样时间复杂度就是\(O(s4^s)\),其中\(s=m-n+1\),能过。

发现在虚树上的一条边转移时,不论该边两个端点状态如何,因为这两个点在原树上之间的形态相同,所以转移系数是相同的。那么暴力求出每个点到它虚树上的父亲的转移系数。这里可以直接暴力,最多把每个点遍历一次。

剩下就是二进制枚举。

这道题也可以用动态DP,可以算是一个模板题。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+50,mod=998244353;
int n,m,ans,a[N];
int head[N],ver[N<<1],nxt[N<<1],tot=1;
int hc[N],vc[N<<1],nc[N<<1],tc;
void add(int u,int v){ver[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
void addc(int u,int v){vc[++tc]=v;nc[tc]=hc[u];hc[u]=tc;}
int fa[N][20],dep[N],dfn[N],Dfn,tr[N<<1],vis[N],x[N],d[N],k,st[N],top;
void dfs(int u){
	dfn[u]=++Dfn;
	for(int i=head[u],v;i;i=nxt[i])
		if(!dfn[v=ver[i]]){
			tr[i]=tr[i^1]=1;
			fa[v][0]=u;dep[v]=dep[u]+1;
			dfs(v);
		}
}
void LCA_pre(){
	for(int j=1;(1<<j)<=n;j++)
		for(int i=1;i<=n;i++)
			fa[i][j]=fa[fa[i][j-1]][j-1];
}
int LCA(int u,int v){
	if(dep[u]<dep[v])swap(u,v);
	int d=dep[u]-dep[v];
	for(int i=17;i>=0;i--)
		if(d&(1<<i))u=fa[u][i];
	if(u==v)return u;
	for(int i=17;i>=0;i--)
		if(fa[u][i]!=fa[v][i])
			u=fa[u][i],v=fa[v][i];
	return fa[u][0];
}
bool cmp(int i,int j){return dfn[i]<dfn[j];}
void vtree(){
	sort(x+1,x+k+1,cmp);st[top=1]=1;
	for(int i=1;i<=k;i++)if(x[i]!=1){
		int g=LCA(x[i],st[top]);
		if(g!=st[top]){
			while(dfn[g]<dfn[st[top-1]])
				addc(st[top-1],st[top]),--top;
			if(dfn[g]!=dfn[st[top-1]])
				addc(g,st[top]),st[top]=g;
			else addc(g,st[top]),--top;
		}
		st[++top]=x[i];
	}
	for(int i=1;i<top;i++)addc(st[i],st[i+1]);
}
int dp[N][2],trans[N][2][2],f[N][2];
void DP_pre(int u){
	dp[u][0]=dp[u][1]=1;
	for(int i=head[u],v;i;i=nxt[i])
		if(tr[i]&&(v=ver[i])!=fa[u][0]){
			DP_pre(v);
			if(!vis[v]){
				dp[u][0]=1ll*dp[u][0]*(dp[v][0]+dp[v][1])%mod;
				dp[u][1]=1ll*dp[u][1]*dp[v][0]%mod;
			}
			else vis[u]=1;
		}
}
void DP(int u){
	f[u][0]=dp[u][0];f[u][1]=dp[u][1];
	if(a[u]!=-1)f[u][1-a[u]]=0;
	for(int i=hc[u],v;i;i=nc[i]){
		DP(v=vc[i]);
		int f0=(1ll*trans[v][0][0]*f[v][0]+1ll*trans[v][0][1]*f[v][1])%mod,
			f1=(1ll*trans[v][1][0]*f[v][0]+1ll*trans[v][1][1]*f[v][1])%mod;
		f[u][0]=1ll*f[u][0]*(f0+f1)%mod;
		f[u][1]=1ll*f[u][1]*f0%mod;
	}
}
int main(){
	memset(a,-1,sizeof(a));
	scanf("%d%d",&n,&m);
	for(int i=1,u,v;i<=m;i++){
		scanf("%d%d",&u,&v);
		add(u,v);add(v,u);
	}
	dfs(1);LCA_pre();
	for(int i=2;i<=tot;i+=2)if(!tr[i]){
		++k;vis[d[k]=x[k]=ver[i]]=1;
		++k;vis[d[k]=x[k]=ver[i^1]]=1;
	}
	DP_pre(1);
	sort(x+1,x+k+1);
	k=unique(x+1,x+k+1)-x-1;
	vtree();
	for(int u=1;u<=n;u++)
		for(int i=hc[u];i;i=nc[i]){
			int v=vc[i];
			trans[v][0][0]=trans[v][1][1]=1;
			for(int x=v;fa[x][0]!=u;x=fa[x][0]){
				int t00=trans[v][0][0],t01=trans[v][0][1],
					t10=trans[v][1][0],t11=trans[v][1][1],y=fa[x][0];
				trans[v][0][0]=1ll*dp[y][0]*(t00+t10)%mod;
				trans[v][0][1]=1ll*dp[y][0]*(t01+t11)%mod;
				trans[v][1][0]=1ll*dp[y][1]*t00%mod;
				trans[v][1][1]=1ll*dp[y][1]*t01%mod;
			}
		}
	for(int i=0;i<(1<<k);i++){
		for(int j=1;j<=k;j++)a[x[j]]=(i>>j-1)&1;
		bool flag=1;
		for(int j=1;j<=m-n+1;j++)
			if(a[d[2*j-1]]&&a[d[2*j]])flag=0;
		if(!flag)continue;
		DP(1);ans=(ans+(f[1][0]+f[1][1])%mod)%mod;
	}
	printf("%d\n",ans);
	return 0;
}

动态DP:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+50;const ll mod=998244353;
int n,m;ll f[N][2],ans;
int head[N],nxt[N<<1],ver[N<<1],tot=1,tr[N<<1];
void add(int u,int v){ver[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
ll power(ll a,ll b){
	ll c=1;
	for(;b;b>>=1){
		if(b&1)c=c*a%mod;
		a=a*a%mod;
	}
	return c;
}
struct Matrix{
	ll a[2][2];
	Matrix (){a[0][0]=a[0][1]=a[1][0]=a[1][1]=0;}
	Matrix operator *(const Matrix&b)const{
		Matrix c;
		c.a[0][0]=(a[0][0]*b.a[0][0]+a[0][1]*b.a[1][0])%mod;
		c.a[1][0]=(a[1][0]*b.a[0][0]+a[1][1]*b.a[1][0])%mod;
		c.a[0][1]=(a[0][0]*b.a[0][1]+a[0][1]*b.a[1][1])%mod;
		c.a[1][1]=(a[1][0]*b.a[0][1]+a[1][1]*b.a[1][1])%mod;
		return c;
	}
}g[N];
int fa[N],top[N],siz[N],L[N],dfn,R[N],son[N],id[N];
void dfs(int u){
	f[u][0]=f[u][1]=1;siz[u]=1;
	for(int i=head[u],v;i;i=nxt[i])
		if(!siz[v=ver[i]]){
			tr[i]=tr[i^1]=1;
			fa[v]=u;dfs(v);siz[u]+=siz[v];
			if(siz[v]>siz[son[u]])son[u]=v;
			f[u][0]=f[u][0]*(f[v][0]+f[v][1])%mod;
			f[u][1]=f[u][1]*f[v][0]%mod;
		}
}
void rdfs(int u,int tp){
	g[u].a[0][0]=g[u].a[1][0]=1;
	L[u]=++dfn;id[dfn]=u;top[u]=tp;R[tp]=dfn;
	if(son[u])rdfs(son[u],tp);
	for(int i=head[u],v;i;i=nxt[i])
		if(tr[i]&&(v=ver[i])!=fa[u]&&v!=son[u]){
			rdfs(v,v);
			g[u].a[0][0]=g[u].a[0][0]*(f[v][0]+f[v][1])%mod;
			g[u].a[1][0]=g[u].a[1][0]*f[v][0]%mod;
		}
	g[u].a[0][1]=g[u].a[0][0];
}
struct SegmentTree{
	Matrix a[N<<2];
	#define mid (l+r>>1)
	void build(int p,int l,int r){
		if(l==r){a[p]=g[id[l]];return;}
		build(p<<1,l,mid);
		build(p<<1|1,mid+1,r);
		a[p]=a[p<<1]*a[p<<1|1];
	}
	void modify(int p,int l,int r,int x){
		if(l==r){a[p]=g[id[l]];return;}
		if(x<=mid)modify(p<<1,l,mid,x);
		else modify(p<<1|1,mid+1,r,x);
		a[p]=a[p<<1]*a[p<<1|1];
	}
	Matrix query(int p,int l,int r,int L,int R){
		if(l>=L&&r<=R)return a[p];
		if(R<=mid)return query(p<<1,l,mid,L,R);
		if(L>mid)return query(p<<1|1,mid+1,r,L,R);
		return query(p<<1,l,mid,L,R)*query(p<<1|1,mid+1,r,L,R);
	}
	#undef mid
}seg;
int a[N],x[50],k,st[N],Top;Matrix g0[N];
vector<int> rej[N];
void update(int u,int op){
	st[++Top]=u,g0[Top]=g[u];
	if(op==0)g[u].a[1][0]=0;
	else g[u].a[0][0]=g[u].a[0][1]=0;
	while(u){
		Matrix lst=seg.query(1,1,n,L[top[u]],R[top[u]]);
		seg.modify(1,1,n,L[u]);
		Matrix now=seg.query(1,1,n,L[top[u]],R[top[u]]);
		u=fa[top[u]];st[++Top]=u,g0[Top]=g[u];
		g[u].a[0][0]=g[u].a[0][0]*(now.a[0][0]+now.a[1][0])%mod
					 *power(lst.a[0][0]+lst.a[1][0],mod-2)%mod;
		g[u].a[1][0]=g[u].a[1][0]*now.a[0][0]%mod
					 *power(lst.a[0][0],mod-2)%mod;
		g[u].a[0][1]=g[u].a[0][0];
	}
}
void clear(int tim){
	while(Top>tim){
		g[st[Top]]=g0[Top];
		seg.modify(1,1,n,L[st[Top]]);
		--Top;
	}
}
void Enum(int p){
	if(p==k+1){
		Matrix res=seg.query(1,1,n,1,R[1]);
		ans=(ans+res.a[0][0]+res.a[1][0])%mod;
		return;
	}
	int tim=Top;
	update(x[p],a[x[p]]=0);Enum(p+1);clear(tim);a[x[p]]=-1;
	update(x[p],a[x[p]]=1);bool flag=1;
	for(auto t:rej[x[p]])if(a[t]==1){flag=0;break;}
	if(flag)Enum(p+1);clear(tim);a[x[p]]=-1;
}
int main(){
	memset(a,-1,sizeof(a));
	scanf("%d%d",&n,&m);
	for(int i=1,u,v;i<=m;i++){
		scanf("%d%d",&u,&v);
		add(u,v);add(v,u);
	}
	dfs(1);rdfs(1,1);seg.build(1,1,n);
	for(int i=2;i<=tot;i+=2)if(!tr[i]){
		x[++k]=ver[i];x[++k]=ver[i^1];
		rej[ver[i]].push_back(ver[i^1]);
		rej[ver[i^1]].push_back(ver[i]);
	}
	sort(x+1,x+k+1);k=unique(x+1,x+k+1)-x-1;
	Enum(1);
	printf("%lld\n",ans);
	return 0;
}

标签:Set,Matrix,int,Top,Solution,II,fa,le,mod
From: https://www.cnblogs.com/by-chance/p/17471243.html

相关文章

  • 【解决git报错 10054】OpenSSL SSL_read: Connection was reset, errno 10054
    使用git获取github上代码时报错:OpenSSLSSL_read:Connectionwasreset,errno10054(此时又必须开着vpn才能访问到github)参考网上的回答,成功解决问题:修改设置,解除ssl验证gitconfig--globalhttp.sslVerify"false"此时,再执行git操作即可。32656@ThinkPad-WeiMINGW64/d/01Te......
  • 【解决git报错 10054】OpenSSL SSL_read: Connection was reset, errno 10054
    使用git获取github上代码时报错:OpenSSLSSL_read:Connectionwasreset,errno10054(此时又必须开着vpn才能访问到github)参考网上的回答,成功解决问题:修改设置,解除ssl验证gitconfig--globalhttp.sslVerify"false"此时,再执行git操作即可。32656@ThinkPad-WeiMINGW64/d/01Te......
  • CSS: offsetTop offsetLeft offsetParent
     offsetParentiscontainingblock 1.position:static;offsetTop元素的上外边距到containingblock的上内边距(containingblock的padding+element.margin)<!DOCTYPEhtml><htmllang="en-US"><head><metacharset="UTF-8"&g......
  • js笔记_Map,Set
    //ES6Mapvarmap=newMap([["tom",100],["jack",100],["jj",100]]);varname=map.get("tom");//通过key获取valuemap.set(‘admin’,123456);//新增或修改map.delete(“tom”);//删除Set:无序不重复的集合set.add(2);//添加set.delete;//删除consol......
  • CSS: offsetWidth offsetHeight clientWidth clientHeight scrollWidth scrollHeight
       <!DOCTYPEhtml><htmllang="en-US"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"cont......
  • #yyds干货盘点# LeetCode程序员面试金典:单词接龙 II
    题目:按字典 wordList完成从单词beginWord到单词endWord转化,一个表示此过程的转换序列是形式上像beginWord->s1->s2->...->sk这样的单词序列,并满足:每对相邻的单词之间仅有单个字母不同。转换过程中的每个单词si(1<=i<=k)必须是字典 wordList中的单词。注意,be......
  • Set A Light 3D Studio Mac三维模拟影棚布光软件
    SetALight3DStudio是一款全新的专业三维模拟影棚灯光布光软件,支持在Mac平台上制作虚拟摄影棚,能够快速制作出真实影棚布光效果,可以使用专业的灯光器材和道具。软件功能强大,操作简单,是一款功能强大的专业三维模拟影棚灯光软件。SetALight3DStudioMac版是一个全新的专业三维模......
  • 用native2ascii.exe实现国际化
    用native2ascii.exe实现国际化用javaSDK/bin目录下的native2ascii.exe把.peoperties文件中的中文转换成unicode字符,实现国际化需要用到javaSDK\\bin目录下的native2ascii.exe程序,把你写的文本文件转成unicode字符即可, native2ascii - Native-to-ASCII Converter将一个文件......
  • rosetta mpi运行错误,libcore.2.so undefined s 的
    重装的ubuntu2004,分别安装了openmpi4.1.1及openmpi1.6.5后编译mpi版本rosetta,运行rosetta_script.mpi.linuxgccrelease均出现libcore.2.so的报错,猜测是mpi版本问题或者是手动安装的mpi编译时出现的问题。后面使用apt重装了ubuntu自带的openmpi4.0.3及lib库,重新编译rosetta,发现能......
  • 自定义系统级无窗口全局快捷键热键-Delphi7_Lite_Full_Edition_Setup_7.3.4.3_Build_2
      自定义系统级无窗口全局快捷键热键-Delphi7_Lite_Full_Edition_Setup_7.3.4.3_Build_20110801-2023年6月9日 programProject1_SetHotkeyBaiduSyncDisk;usesForms,Unit1_SetHotkeyBaiduSyncDiskin'Unit1_SetHotkeyBaiduSyncDisk.pas'{Form1};{$R*.res}b......