1. 程式人生 > 實用技巧 >模擬賽41 題解

模擬賽41 題解

T1

考場上一看到暴力有70分就沒有去想正解。當時腦子裡閃過了先處理兩個相加,再詢問。但是當時感覺可能會算重複,就沒有繼續往下想。
但是應該是沒有重複的。因為順序不同也算不同方案。。
因為100000內的質數只有9000多個,所以可以定義dp[i]為i能被兩個質數相加得到的方案數。然後\(n^2\)求出。
對於每個n,只需O(n)求出答案即可。

程式碼:


#include <bits/stdc++.h>
using namespace std;  
typedef long long ll;
const int maxn=100000+10;
int read(){
	int w=0,x=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') x=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		w=(w<<1)+(w<<3)+(ch^48);
		ch=getchar();
	}
	return x*w;
}
int n,cnt;
int prime[maxn];
bool is_not_prime[maxn];
ll dp[maxn<<1];
ll ans;
void xxs(){
	is_not_prime[0]=is_not_prime[1]=1;
	for(register int i=2;i<=100000;++i){
		if(!is_not_prime[i]) prime[++cnt]=i;
		for(register int j=1;j<=cnt&&i*prime[j]<=100000;++j){
			is_not_prime[prime[j]*i]=1;
			if(i%prime[j]==0) break;
		}
	}
	for(register int i=1;i<=cnt;++i){
		for(register int j=1;j<=cnt;++j){
			if(prime[i]+prime[j]<=100000) dp[prime[i]+prime[j]]++;
		}
	}
}
void Solve(){
	xxs();
	int T=read();
	while(T--){
		n=read();
		ll ans=0;
		for(register int i=1;i<=n;++i) ans+=dp[i]*dp[n-i];
		printf("%lld\n",ans);
	}
}
int main(){
	freopen("plus.in","r",stdin);
	freopen("plus.out","w",stdout);
	Solve();
	return 0;
}

T2

轉化為01trie。發現對於[l,r],假如兩個區間[l,mid],[mid+1,r]完全相同,那麼就是這一位取0或1都行於是返回F(l,mid)2。
如果兩個區間沒有交,那麼就是分開討論,再相乘,即F(l,mid+1)
F(mid+1,r);
如果兩種情況都沒出現,那麼一定無解。
邊界F(x,x)=1;
(其實可以先在OJ上交一發printf('0');,然後發現0分,證明沒有無解的情況,於是每次比較兩個區間的時候只需要比較第一個元素即可,然後就跑成了最優解233)

程式碼:

#include <bits/stdc++.h>
using namespace std;
const int maxn=1<<17,mod=1e9+7;
#define gc() (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? EOF : *p1++) : *p1++)
#define read() ({ register int x = 0, f = 1; register char c = gc(); while(c < '0' || c > '9') { if (c == '-') f = -1; c = gc();} while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = gc(); f * x; })
char buf[1 << 20], *p1, *p2;
int m,n;
int p[maxn];
int ans;
int Devide(int l,int r){
	if(l==r) return 1;
	int mid=(l+r)>>1;
	bool flag=0;
	if(p[l]==p[mid+1]) return 2*Devide(l,mid)%mod;
	return 1ll*Devide(l,mid)*Devide(mid+1,r)%mod;
}
void Solve(){
	m=read();
	n=read();
	for(int i=1;i<=(1<<m);++i) p[i]=read();
	ans=Devide(1,1<<m);
	printf("%d\n",ans);
}
int main(){
	freopen("match.in","r",stdin);
	freopen("match.out","w",stdout);
	Solve();
	return 0;
}


T3

這題轉化完了之後竟然是原題。。操
發現一條邊是黑邊的條件,就是兩個端點被不同的修改操作修改過。
因此可以打時間戳,最後詢問路徑有多少連續相等的段。
於是就是luogu P2486 [SDOI2011]染色了,具體怎麼維護連結裡有。

程式碼:

#include <bits/stdc++.h>
using namespace std;
const int maxn=500000+10,Inf=0x3f3f3f3f;
struct node{
	int to,next;
}edge[maxn<<1];
int head[maxn],top[maxn],size[maxn],son[maxn],fa[maxn],depth[maxn],dfn[maxn];
int n,m,cnt,Time,tim;
struct Segment_tree{
	int val,lazy,lc,rc;//lc,rc分別表示這個區間左右端點的color,lazy==-1時表示沒有賦值
}tree[maxn<<2];
int read(){
	int w=0,x=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') x=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		w=(w<<1)+(w<<3)+(ch^48);
		ch=getchar();
	}
	return x*w;
}
void add(int from,int to){
	edge[++cnt].to=to;
	edge[cnt].next=head[from];
	head[from]=cnt;
}
void dfs1(int u,int f){
	size[u]=1;
	fa[u]=f;
	for(int i=head[u];i;i=edge[i].next){
		int v=edge[i].to;
		if(v==f) continue;
		depth[v]=depth[u]+1;
		dfs1(v,u);
		size[u]+=size[v];
		if(size[v]>size[son[u]]) son[u]=v;
	}
}
void dfs2(int u,int t){
	top[u]=t;
	dfn[u]=++Time;
	if(son[u]) dfs2(son[u],t);
	for(int i=head[u];i;i=edge[i].next){
		int v=edge[i].to;
		if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
	}
}
void pushup(int rt){
	tree[rt].lc=tree[rt<<1].lc;
	tree[rt].rc=tree[rt<<1|1].rc;
	tree[rt].val=tree[rt<<1].val+tree[rt<<1|1].val-(tree[rt<<1].rc==tree[rt<<1|1].lc);
}
void update(int rt,int x){
	tree[rt].lazy=x;
	tree[rt].val=1;
	tree[rt].lc=tree[rt].rc=x;
}
void pushdown(int rt){
	if(tree[rt].lazy==-1) return;
	tree[rt].val=1;
	update(rt<<1,tree[rt].lazy);
	update(rt<<1|1,tree[rt].lazy);
	tree[rt].lazy=-1;
}
void modify(int rt,int l,int r,int s,int t,int p){
	if(s<=l&&r<=t){
		update(rt,p);
		return;
	}
	int mid=(l+r)>>1;
	pushdown(rt);
	if(s<=mid) modify(rt<<1,l,mid,s,t,p);
	if(t>mid) modify(rt<<1|1,mid+1,r,s,t,p);
	pushup(rt);
}
void build(int rt,int l,int r){
	tree[rt].lazy=-1;
	if(l==r){
		tree[rt].val=1;
		tree[rt].lc=tree[rt].rc=l;
		return;
	}
	int mid=(l+r)>>1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid+1,r);
	pushup(rt);
}
int query2(int rt,int l,int r,int x){
	if(l==r) return tree[rt].lc;
	int mid=(l+r)>>1;
	pushdown(rt);
	if(x<=mid) return query2(rt<<1,l,mid,x);
	else return query2(rt<<1|1,mid+1,r,x);
}
int query(int rt,int l,int r,int s,int t){
	if(s<=l&&r<=t) return tree[rt].val;
	int mid=(l+r)>>1;
	pushdown(rt);
	if(t<=mid) return query(rt<<1,l,mid,s,t);
	if(s>mid) return query(rt<<1|1,mid+1,r,s,t);
	return query(rt<<1,l,mid,s,t)+query(rt<<1|1,mid+1,r,s,t)-(tree[rt<<1].rc==tree[rt<<1|1].lc);
}
int Query(int u,int v){
	if(u==v) return 1;
	int res=0;
	while(top[u]!=top[v]){
		if(depth[top[u]]<depth[top[v]]) swap(u,v);
		//printf("u==%d v==%d\n",u,v);
		res+=query(1,1,n,dfn[top[u]],dfn[u]);
		//printf("dfn[top[u]]=%d dfn[u]=%d\n",dfn[top[u]],dfn[u]);
		if(top[u]!=1){
			int sss=query2(1,1,n,dfn[top[u]]);
			int ssss=query2(1,1,n,dfn[fa[top[u]]]);
			//printf("sss=%d ssss=%d\n",sss,ssss);
			if(sss==ssss) res--;	
			//if(top[u]!=1 && query2(1,1,n,dfn[top[u]])==query2(1,1,n,dfn[fa[top[u]]])) res--;
		}
		u=fa[top[u]];
	}
	if(depth[u]>depth[v]) swap(u,v);
	res+=query(1,1,n,dfn[u],dfn[v]);
	return res;
}
void Modify(int u,int v,int x){
	while(top[u]!=top[v]){
		if(depth[top[u]]<depth[top[v]]) swap(u,v);
		modify(1,1,n,dfn[top[u]],dfn[u],x);
		u=fa[top[u]];
	}
	if(depth[u]>depth[v]) swap(u,v);
	modify(1,1,n,dfn[u],dfn[v],x);	
}
void Solve(){
	n=read();
	for(int i=1,x,y;i<n;++i){
		x=read();
		y=read();
		add(x,y);
		add(y,x);
	}
	dfs1(1,0);
	dfs2(1,1);
	build(1,1,n);
	//for(int i=1;i<=n;++i) printf("fa[%d]=%d son[%d]=%d depth[%d]=%d top[%d]=%d size[%d]=%d dfn[%d]=%d\n",i,fa[i],i,son[i],i,depth[i],i,top[i],i,size[i],i,dfn[i]);
	m=read();
	tim=n;
	for(int i=1,op,x,y,z;i<=m;++i){
		op=read();
		x=read();
		y=read();
		if(op==0){
			int res=Query(x,y);
			printf("%d\n",res-1);
		}
		else{
			tim++;
			Modify(x,y,tim);
		}
	}
}
int main(){
	freopen("colour.in","r",stdin);
	freopen("colour.out","w",stdout);
	Solve();
	return 0;
}

T4

不會