NOIP2009提高组题解

\(D1T1\) 潜伏者 \((OK)\)

\(D1T2\) \(Hankson\)的趣味题 \((OK)\)

\(D1T3\) 最优贸易 \((OK)\)

\(D1T4\) 靶形数独 \((OK)\)

这四道之前都做过,所以再做一次还是挺快的.

\(T1\)字符串模拟题,不想讲,不难.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=105;
int a[N],b[N];
char s1[N],s2[N],s3[N];
int main(){
	scanf("%s%s%s",s1+1,s2+1,s3+1);
	int n=strlen(s1+1),m=strlen(s2+1);
	if(n!=m){puts("Failed");return 0;}
	for(int i=1;i<=n;++i){
		if(a[s1[i]-'A'+1]!=0&&a[s1[i]-'A'+1]!=s2[i]-'A'+1){
			puts("Failed");return 0;
		}
		if(b[s2[i]-'A'+1]!=0&&b[s2[i]-'A'+1]!=s1[i]-'A'+1){
			puts("Failed");return 0;
		}
		a[s1[i]-'A'+1]=s2[i]-'A'+1;
		b[s2[i]-'A'+1]=s1[i]-'A'+1;
	}
	for(int i=1;i<=26;++i)
		if(!a[i]){puts("Failed");return 0;}
	int k=strlen(s3+1);
	for(int i=1;i<=k;++i){
		printf("%c",(char)(a[s3[i]-'A'+1]-1+'A'));
	}printf("\n");
    return 0;
}

\(T2\)暴力就可以水过去,因为\(lcm(x,c)=d\),所以\(x\)一定是\(d\)的约数,所以\(O(\sqrt d)\)枚举\(d\)的所有约数,然后同时对那两个式子进行判断是否合法即可.

第一个\(gcd(x,a)=b\)可以直接判断,然后对于第二个\(lcm(x,c)=d\),因为\(gcd(x,y)*lcm(x,y)=x*y\),所以有\(d=\frac{x*c}{gcd(x,c)}\),判断这个式子即可.

其实这样做的理论时间复杂度是\(n\sqrt dlog_d\),对于\(n<=2000,d<=2e9\)来说是等于\(831909413\),然后因为肯定跑不满,所以本题才能水过去.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline ll read(){
    ll x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
inline ll gcd(ll a,ll b){
	if(!b)return a;
	return gcd(b,a%b);
}
int main(){
	int n=read();
	while(n--){
		ll a=read(),b=read(),c=read(),d=read(),ans=0;
		for(int i=1;i*i<=d;++i){
			if(d%i==0){
				ll x=i;
				if(gcd(a,x)==b){
					if((c*x)/gcd(c,x)==d)++ans;
				}
				if(i*i!=d){
					x=d/i;
					if(gcd(a,x)==b){
						if((c*x)/gcd(c,x)==d)++ans;
					}
				}
			}
		}
		printf("%lld\n",ans);
	}
    return 0;
}

\(T3\)建正图跑一次\(spfa/dij\),记录\(minn[i]\)表示\(1\)号节点到节点\(i\)的路径中的最小买进价格,然后建反图跑一次\(spfa/dij\),记录\(maxn[i]\)表示节点\(n\)到节点\(i\)的路径中的最大卖出价格.最后扫描所有节点,取最大的\(maxn[i]-minn[i]\)即可.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=1e5+5;
const int M=5e5+5;
int n,m,ans,a[M],b[M],c[M];
int val[N],visit[N],minn[N],maxn[N];
int tot,head[N],nxt[M<<1],to[M<<1];
queue<int>q;
inline void add(int a,int b){nxt[++tot]=head[a];head[a]=tot;to[tot]=b;}
int main(){
	n=read();m=read();
	for(int i=1;i<=n;++i)val[i]=read();
	for(int i=1;i<=m;++i){
		a[i]=read(),b[i]=read();c[i]=read();
		add(a[i],b[i]);if(c[i]==2)add(b[i],a[i]);
	}
	q.push(1);visit[1]=1;memset(minn,0x3f,sizeof(minn));minn[1]=val[1];
	while(q.size()){
		int u=q.front();q.pop();visit[u]=0;
		for(int i=head[u];i;i=nxt[i]){
			int v=to[i];
			if(minn[v]>min(minn[u],val[v])){
				minn[v]=min(minn[u],val[v]);
				if(!visit[v])visit[v]=1,q.push(v);
			}
		}
	}
	tot=0;memset(head,0,sizeof(head));
	for(int i=1;i<=m;++i){add(b[i],a[i]);if(c[i]==2)add(a[i],b[i]);}
	q.push(n);visit[n]=1;maxn[n]=val[n];
	while(q.size()){
		int u=q.front();q.pop();visit[u]=0;
		for(int i=head[u];i;i=nxt[i]){
			int v=to[i];
			if(maxn[v]<max(maxn[u],val[v])){
				maxn[v]=max(maxn[u],val[v]);
				if(!visit[v])visit[v]=1,q.push(v);
			}
		}
	}
	for(int i=1;i<=n;++i)ans=max(ans,maxn[i]-minn[i]);
	printf("%d\n",ans);
    return 0;
}

\(T4\)就只有一个剪枝:优化搜索顺序.每一次从状态量最少的行开始搜,这个可以预处理.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
int a[10][10],hang[10][10],lie[10][10],ge[10][10];
int now,ans,tot,dfs[100][5];
struct node{int num,sum;}line[10];
inline bool cmp(node x,node y){return x.sum<y.sum;}
inline int calc(int i,int j){return (i-1)/3*3+(j-1)/3+1;}
inline int point(int x,int y){
	if(x==5&&y==5)return 10;
	if(x>=4&&x<=6&&y>=4&&y<=6)return 9;
	if(x>=3&&x<=7&&y>=3&&y<=7)return 8;
	if(x>=2&&x<=8&&y>=2&&y<=8)return 7;
	return 6;
}
inline void DFS(int ord,int has){
	if(ord>tot){
		if(has>ans)ans=has;
		return;
	}
	for(int i=1;i<=9;++i){
		if(hang[dfs[ord][1]][i])continue;
		if(lie[dfs[ord][2]][i])continue;
		if(ge[dfs[ord][3]][i])continue;
		hang[dfs[ord][1]][i]=1;
		lie[dfs[ord][2]][i]=1;
		ge[dfs[ord][3]][i]=1;
		DFS(ord+1,has+dfs[ord][4]*i);
		hang[dfs[ord][1]][i]=0;
		lie[dfs[ord][2]][i]=0;
		ge[dfs[ord][3]][i]=0;
	}
}
int main(){
	for(int i=1;i<=9;++i)line[i].num=i;
	for(int i=1;i<=9;++i)
		for(int j=1;j<=9;++j){
			a[i][j]=read();
			if(!a[i][j]){++line[i].sum;continue;}
			hang[i][a[i][j]]=1;
			lie[j][a[i][j]]=1;
			ge[calc(i,j)][a[i][j]]=1;
			now+=point(i,j)*a[i][j];
		}
	sort(line+1,line+9+1,cmp);
	for(int i=1;i<=9;++i)
		for(int j=1;j<=9;++j){
			if(a[line[i].num][j])continue;
			dfs[++tot][1]=line[i].num;
			dfs[tot][2]=j;
			dfs[tot][3]=calc(line[i].num,j);
			dfs[tot][4]=point(line[i].num,j);
		}
	DFS(1,now);if(!ans)puts("-1");else printf("%d\n",ans);
    return 0;
}

posted on 2019-11-05 20:45  PPXppx  阅读(133)  评论(0编辑  收藏  举报