191012CSP-J模拟题解

T2算答案加成了矩阵的一行然后调了我2个小时

T1:
求图的仅在一个简单环中的边
显然点双
Code:

#include
#define pb push_back
#define fi first
#define se second
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=1000005;
int adj[N],in[N],nxt[N<<1],to[N<<1],cnt=1;
inline void addedge(int u,int v){nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;}
int dfn[N],low[N],tim,id[N],bcc,num[N],ee[N],ans[N];
int stk[N],top,n,m,vis[N];
pair<int,int> E[N];
vector<int> cir[N];
void dfs(int u,int fa){
	dfn[u]=low[u]=++tim;
	stk[++top]=u;
	for(int e=adj[u];e;e=nxt[e]){
		int v=to[e];
		if(v==fa)continue;
		if(!dfn[v]) dfs(v,u),low[u]=min(low[u],low[v]);
		else {low[u]=min(low[u],dfn[v]);continue;}
		if(low[v]>=dfn[u]){
			int tmp;
			bcc++;
			do{
				tmp=stk[top];
				cir[bcc].pb(tmp);
				num[bcc]++;
				top--;
			}while(tmp!=v);
			cir[bcc].pb(u);
			num[bcc]++;
		}		
	}
}
inline void file(){freopen("graph.in","r",stdin);freopen("graph.out","w",stdout);}
int main(){
	n=read(),m=read();
	for(int i=1;i<=m;i++){
		int u=read(),v=read();
		E[i].fi=u,E[i].se=v;
		addedge(u,v),addedge(v,u);
	}
	dfs(1,0);
	for(int i=1;i<=bcc;i++){
		for(int j=0;j<cir[i].size();j++) id[cir[i][j]]=i;
		for(int j=0;j<cir[i].size();j++){
			int u=cir[i][j];
			for(int e=adj[u];e;e=nxt[e]){
				int v=to[e];
				if(id[v]==id[u]&&dfn[u]>dfn[v]){ee[i]++;ans[i]^=e>>1;}
			}
		}
	}
	int res=0;
	for(int i=1;i<=bcc;i++) if(ee[i]==num[i])res^=ans[i];
	cout<<res;
	return 0;
}

T2:求长度为n的最大价值的串,串中每出现一个给定子串价值会加上一个对应的给定值
串总和200,n规模1e12
显然矩阵快速幂优化AC自动机上DP

Code:

#include
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second
#define db double
using namespace std;
inline ll read(){
	ll res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=205,M=201;
const ll INF=1e18;
int cnt=0;
struct Mat{
	ll a[M][M];
	inline void init(){
		for(int i=0;i<=cnt;++i)
			for(int j=0;j<=cnt;++j) a[i][j]=-INF;
	}
	inline Mat operator * (const Mat &b)const{
		Mat res;
		res.init();
		for(int i=0;i<=cnt;++i)
			for(int k=0;k<=cnt;++k) if(a[i][k]!=-INF)
				for(int j=0;j<=cnt;++j) if(b.a[k][j]!=-INF)
					res.a[i][j]=max(res.a[i][j],a[i][k]+b.a[k][j]);
		return res;
	}
}trans,bs;
inline Mat ksm(Mat a,ll b){
	Mat res=a;
	for(;b;b>>=1,a=a*a) if(b&1) res=res*a;
	return res;
}
char s[N];
namespace ACAM{
	struct trie{
		int son[26];
		ll val;
	}tr[N*10];
	inline void ins(int len,ll w){
		int now=0;
		for(int i=1;i<=len;i++){
			if(!tr[now].son[s[i]-'a']) tr[now].son[s[i]-'a']=++cnt;
			now=tr[now].son[s[i]-'a'];
		}
		tr[now].val+=w;
	}
	int fail[N*10];
	inline void buildfail(){
		queue<int>q;
		for(int i=0;i<26;i++) if(tr[0].son[i]) q.push(tr[0].son[i]);
		while(!q.empty()){
			int x=q.front();q.pop();
			for(int i=0;i<26;i++){
				if(tr[x].son[i]) fail[tr[x].son[i]]=tr[fail[x]].son[i],q.push(tr[x].son[i]),tr[tr[x].son[i]].val+=tr[fail[tr[x].son[i]]].val;
				else tr[x].son[i]=tr[fail[x]].son[i];
			}
		}
	}
	inline void buildmartix(){
		for(int i=0;i<=cnt;i++)
			for(int j=0;j<26;j++) trans.a[tr[i].son[j]][i]=tr[tr[i].son[j]].val;
	}
}
using namespace ACAM;
ll a[N];
inline void file(){freopen("string.in","r",stdin);freopen("string.out","w",stdout);}
int main(){
	ll n=read();int m=read();
	for(int i=1;i<=m;i++) a[i]=read();
	for(int i=1;i<=m;i++){
		scanf("%s",s+1);int len=strlen(s+1);
		ins(len,a[i]);
	}
	buildfail();
	trans.init();
	buildmartix();
	trans=ksm(trans,n-1);
	ll ans=0;
	for(int i=0;i<M;i++) ans=max(ans,trans.a[i][0]);
	cout<<ans<<endl;
	return 0;
}

T3:有n个位置,某些位置有初始数,再给出m个限制,形如 [ l , r ] [l,r] [l,r]中有k个位置的数严格大于这个区间的其他数,求合法解或者无解,给出的位置总和不超过3e5,位置不超过1e5,限制不超过2e5
显然线段树优化建图+拓扑排序

Code:

#include
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second
#define db double
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=5e6+5;
int n;
int p[N<<1],val[N],a[N];
int vis[N<<1],head[N],nxt[N<<1],tot=0,c[N<<1],in[N];
inline void add(int x,int y,int z){in[y]++;vis[++tot]=y;c[tot]=z;nxt[tot]=head[x];head[x]=tot;}
int cnt=0;
inline void build(int k,int l,int r){
	if(l==r){p[k]=l;return;}
	p[k]=++cnt;
	int mid=l+r>>1;
	build(k<<1,l,mid),build(k<<1|1,mid+1,r);
	add(p[k<<1],p[k],0),add(p[k<<1|1],p[k],0);
}
inline void modify(int k,int l,int r,int ql,int qr,int pos){
	if(ql<=l && r<=qr) return add(p[k],pos,1);
	int mid=l+r>>1;
	if(ql<=mid) modify(k<<1,l,mid,ql,qr,pos);
	if(qr>mid) modify(k<<1|1,mid+1,r,ql,qr,pos); 
}
bool f=0;
inline bool topsort(){
	queue<int>q;
	for(int i=1;i<=cnt;i++) if(!in[i]) q.push(i);
	while(!q.empty()){
		int x=q.front();q.pop();
		if(val[x]>1e9 || (a[x] && val[x]>a[x])) return false;
		val[x]=max(1,max(val[x],a[x]));
		for(int i=head[x];i;i=nxt[i]){
			int y=vis[i];
			val[y]=max(val[y],val[x]+c[i]);
			--in[y];if(in[y]==0) q.push(y);
		}
	}
	for(int i=1;i<=n;i++) if(in[i]) return false;
	f=1;return true;
}
int main(){
	n=read();cnt=n;int s=read(),m=read();
	for(int i=1;i<=s;i++){int x=read();a[x]=read();}
	build(1,1,n);
	while(m--){
		int l=read(),r=read(),k=read();
		int last=l-1,inode=++cnt;
		for(int i=1;i<=k;i++){
			int x=read();
			add(inode,x,0);
			if(last+1<=x-1) modify(1,1,n,last+1,x-1,inode);
			last=x;
		}
		if(last+1<=r) modify(1,1,n,last+1,r,inode);
	}
	puts(topsort()?"Possible":"Impossible");
	if(f) for(int i=1;i<=n;i++) cout<<val[i]<<" ";
	return 0;
}

你可能感兴趣的:(线段树,ACAM,连通性)