NOIP 2018.10.4

【口胡】

快速幂一位一位算就行了

#include<bits/stdc++.h>
using namespace std;
char a[100010];
int rest,now,K,t;
int quick_pow(int a,int b,int mod){
	int ret=1;
	while(b){
		if(b&1) ret=ret*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return ret;
}
int main(){
/*	freopen("kbased.in","r",stdin);
	freopen("kbased.out","w",stdout);*/
	scanf("%d",&t);
	while(t--){
		rest=0;
		scanf("%d",&K);
		scanf("%s",a);
		int len=strlen(a);
		for(int i=len-1;i>=0;--i){
			if(a[i]>='0'&&a[i]<='9') now=a[i]-'0';
			if(a[i]>='A'&&a[i]<='F') now=a[i]-'A'+10;
			rest=(rest+quick_pow(K,len-i-1,K-1)*now)%(K-1);
		}
		if(rest==0) printf("yes\n");
		else printf("no\n");
	}
	return 0;
}

————————————————————————————————————————————————————————

【口胡】

SCC+DFS

具体做法:先缩点,整个图变成一颗树,然后两次DFS求出直径AB,

到x的最远距离是MAX(dis(x,A),dis(x,B))。

小证一下正确性:

假设AB是这颗树的直径,并且存在一个结点C,使得  x到C的距离  大于  max(x到A的距离,x到B的距离)。

不妨设x到A的距离大于x到B的距离。那么直径就会变成AC(红色部分),矛盾。

所以到x的最远距离是max(dis(x,A),dis(x,B))。

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=20010;
const int maxm=400040;//双向边,开两倍!! 
int root,N,M,a,b,c,cnt=0,ent=0,top=0,sz=0,ddd=0,mx=0;

int st[maxn],ins[maxn],low[maxn],dfsn[maxn],belong[maxn];//缩点用 

int Head[maxn],Next[maxm],V[maxm],W[maxm];//原图信息 
int head[maxn],next[maxm],v[maxm],w[maxm];//缩完后,每个集合是一个点,存集合信息 

ll disa[maxn],dis[maxn];

void Add(int u,int v,int w){
	++ent;
	Next[ent]=Head[u];
	V[ent]=v;
	W[ent]=w;
	Head[u]=ent;
}
void addedge(int u,int v,int w){Add(u,v,w),Add(v,u,w);}

void addd(int U,int V,int W){
	++ddd;
	next[ddd]=head[U];
	v[ddd]=V;
	w[ddd]=W;
	head[U]=ddd;
}
void adddedge(int u,int v,int w){addd(u,v,w),addd(v,u,w);}

//tarjan模板,belong[i]表示i所在集合 
void tarjan(int u,int fa){
	st[++top]=u,ins[u]=1;
	dfsn[u]=low[u]=++sz;
	for(int i=Head[u];i!=-1;i=Next[i]){
		int v=V[i];
		if(v==fa) continue;
		if(!dfsn[v]){
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
		}
		else if(ins[v]) low[u]=min(low[u],dfsn[v]);
	}
	if(dfsn[u]==low[u]){
		int j;cnt+=1;
		while(j!=u){
			j=st[top--];
			ins[j]=0;
			belong[j]=cnt;
		}
	}
}

//两次dfs,求直径。利用了刚刚证的性质
//第一次dfs随便找一个点为根,搜到直径的一个端点A。 搜完后把mx值和dis值要初始化为0,供下次搜索使用 。 
//第二次dfs以A为根,搜索过程中求距离:dis[i]表示i到A的距离。搜完后得到另一个端点B。 
void dfs(int u,int fa){
	for(int i=head[u];i!=-1;i=next[i]){
		int V=v[i];
		if(V==fa) continue;
		dis[V]=dis[u]+w[i];
		if(dis[V]>mx) mx=dis[V],root=V;
		dfs(V,u);
	}
}

//求每个点到B的距离:disa[i]表示i到B的距离。 
void dfss(int u,int fa){
	for(int i=head[u];i!=-1;i=next[i]){
		int V=v[i];
		if(V==fa) continue;
		disa[V]=disa[u]+w[i];
		dfss(V,u);
	}
}

void read(int &x){
	x=0;char ch=getchar();
	while(ch>'9'||ch<'0') ch=getchar();
	while(ch<='9'&&ch>='0') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
}

int main(){
	memset(head,-1,sizeof(head));
	memset(next,-1,sizeof(next));
	memset(Head,-1,sizeof(Head));
	memset(Next,-1,sizeof(Next));
	read(N),read(M);
	for(int i=1;i<=M;++i){
		read(a),read(b),read(c);
		addedge(a,b,c);
	}
	for(int i=1;i<=N;++i)
	if(!dfsn[i]) tarjan(i,0);
	
	/*
	对于每个点,如果与它有连线的点和它
	不在同一个集合,就把这两个集合连起来。 
	*/
	for(int i=1;i<=N;++i)
		for(int j=Head[i];j!=-1;j=Next[j])
			if(belong[i]!=belong[V[j]])
				addd(belong[i],belong[V[j]],W[j]);
	
	dfs(1,-1);
	mx=0,memset(dis,0,sizeof(dis));
	dfs(root,-1);
	mx=0;
	dfss(root,-1);
	
	
	for(int i=1;i<=N;++i) printf("%lld\n",max(dis[belong[i]],disa[belong[i]]));
}

【口胡】

树形DP做法:

int s[maxn],S[maxn],cd[maxn],g[maxn],ans[maxn];
/*
s[i]表示从儿子转移过来
S[i]表示从哪个儿子转移过来
cd[i]表示儿子中的次大值
g[i]表示从父亲转移过来
ans[i]存答案
*/
void dfs(int u,int fa){
	for(int i=head[u];i!=-1;i=next[i]) if(v[i]!=fa)
	{
		dfs(v[i],u);
		if(s[v[i]]+w[i]>s[u]){
			cd[u]=s[u];
			s[u]=s[v[i]]+w[i];
			S[u]=v[i];
		}
		else cd[u]=max(cd[u],s[v[i]]+w[i]);
	}
}

void DFS(int u,int fa){
	for(int i=head[u];i!=-1;i=next[i]) if(v[i]!=fa)
	{
		if(v[i]==S[u])
			g[v[i]]=max(g[u],cd[u])+w[i];
		else
			g[v[i]]=max(g[u],s[u])+w[i];
		DFS(v[i],u);
	}
}

先从儿子转移,s[i]表示i到叶结点的最大值。

再从父亲转移,g[i]表示从i的父结点到i的最大值。

记录一下s[i]的次大,防止g[i]转移的时候出问题,如下:

    若s[u]从v转移过来,那么g[v]就不能用max(g[u],s[u])+w[i]转移,这样会把w[i]算两次。所以在s转移的时候记录一个次大值。当出现这种情况的时候用次大值转移就行了--g[v]=max(g[u],cd[u])+w[i]。

——————————————————————————————————————————————————————

猜你喜欢

转载自blog.csdn.net/g21wcr/article/details/82937022