• 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("
    ");
        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)}),判断这个式子即可.

    其实这样做的理论时间复杂度是(nsqrt 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
    ",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
    ",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
    ",ans);
        return 0;
    }
    
    
  • 相关阅读:
    如何抓住用户痛点做产品?
    分析需求场景对产品设计的意义
    【用户分析-用户场景】这TM才是产品思维!
    WebUploader实现浏览器端大文件分块上传
    npm 安装包报错 rollbackFailedOptional
    PAT 甲级 1074 Reversing Linked List (25 分)(链表部分逆置,结合使用双端队列和栈,其实使用vector更简单呐)...
    PAT 甲级 1071 Speech Patterns (25 分)(map)
    P3370 【模板】字符串哈希
    PageRank算法原理与Python实现
    PAT-2019年冬季考试-甲级 7-4 Cartesian Tree (30分)(最小堆的中序遍历求层序遍历,递归建树bfs层序)...
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11801501.html
Copyright © 2020-2023  润新知