NOIP2009 题解

潜伏者

题解:

简单的字符串模拟,是一道签到题。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
char s1[maxn];
char s2[maxn];
char p[maxn];
int mp[maxn];
int mp1[maxn];
int main(){
    scanf("%s",s1+1);
    scanf("%s",s2+1);
    scanf("%s",p+1);
    int len=strlen(s1+1);
    int len2=strlen(p+1);
    for(int i=1;i<=len;i++){
        if(!mp[s1[i]-'A'+1]) mp[s1[i]-'A'+1]=s2[i]-'A'+1;
        else{
            if(mp[s1[i]-'A'+1]!=s2[i]-'A'+1){
                printf("Failed
");
                return 0;
            }
        }
        if(!mp1[s2[i]-'A'+1]) mp1[s2[i]-'A'+1]=s1[i]-'A'+1;
        else{
            if(mp1[s2[i]-'A'+1]!=s1[i]-'A'+1){
                printf("Failed
");
                return 0;
            }
        }
    }
    for(int i=1;i<=26;i++){
        if(!mp[i]){
            printf("Failed
");
            return 0;
        }
    } 
    for(int i=1;i<=len2;i++) printf("%c",mp[p[i]-'A'+1]+'A'-1);
    printf("
");
    return 0;
}
View Code

hankson的趣味题

题解:

50分暴力有手就能写,但是我们肯定要想正解。

100分正解:还是不太容易想到,参考了一本通上的做法。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int tot;
int n;
int a0,a1,b0,b1; 
int gcd(int a,int b){
    if(!b) return a;
    return gcd(b,a%b);
}
int lcm(int a,int b){
    return a*b/gcd(a,b);
}
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        tot=0;
        scanf("%lld%lld%lld%lld",&a0,&a1,&b0,&b1);
        if(b1%b0){
            printf("0
");
            continue;
        }
        int x;
        for(int j=1;j<sqrt(b0);j++){
            if(b0%j==0){
                x=(b1/b0)*j;
                if(gcd(x,b0)==j&&gcd(x,a0)==a1) tot++;
                x=(b1/b0)*(b0/j);
                if(gcd(x,b0)==b0/j&&gcd(x,a0)==a1) tot++;
            }
        }
        int k=(int)sqrt(b0);
        if(k*k==b0&&b0%k==0){
            x=(b1/b0)*k;
            if(gcd(x,b0)==k&&gcd(x,a0)==a1) tot++;
        }
        printf("%lld
",tot);
    }
    return 0;
}
View Code

最优贸易

题解:

暑假讲过这道题,思想非常常见,有向图建反边,然后更新最大值最小值即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
const int INF=0x3f3f3f3f;
struct node{
    int nxt;
    int to;
}edge[maxn*2];
struct node1{
    int nxt;
    int to;
}edge1[maxn*2];
int x,y,z;
int n,m; 
int head[maxn],cnt;
int val[maxn];
int mi[maxn],mx[maxn];
bool vis[maxn];
void add(int x,int y){
    edge[++cnt].nxt=head[x];
    edge[cnt].to=y;
    head[x]=cnt;
}
int head2[maxn],cnt2;
void add2(int x,int y){
    edge1[++cnt2].nxt=head2[x];
    edge1[cnt2].to=y;
    head2[x]=cnt2;
}
queue<int> q;
void spfa1(){
    for(int i=1;i<=n;i++){
        mi[i]=INF;
        vis[i]=false;
    }
    mi[1]=val[1];
    q.push(1);
    vis[1]=true;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=edge[i].nxt){
            int v=edge[i].to;
            if(mi[v]>min(mi[u],val[v])){
                mi[v]=min(mi[u],val[v]);
                if(!vis[v]){
                    q.push(v);
                    vis[v]=true;
                }
            }
        }
    }
}
void spfa2(){
    for(int i=1;i<=n;i++){
        mx[i]=-INF;
        vis[i]=false;
    }
    mx[n]=val[n];
    q.push(n);
    vis[n]=true;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=head2[u];i;i=edge1[i].nxt){
            int v=edge1[i].to;
            if(mx[v]<max(mx[u],val[v])){
                mx[v]=max(mx[u],val[v]);
                if(!vis[v]){
                    q.push(v);
                    vis[v]=true;
                }
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&val[i]);
    }
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&z);
        if(z==1){
            add(x,y);
            add2(y,x);
        } 
        else{
            add(x,y);
            add(y,x);
            add2(x,y);
            add2(y,x); 
        }
    }
    spfa1();
    spfa2();
    int ans=0;
    for(int i=1;i<=n;i++){
        ans=max(ans,mx[i]-mi[i]);
    } 
    printf("%d
",ans);
    return 0;
} 
View Code

靶形数独

题解:

一开始我写的是50分的填数独,非常naive。

这题是一道搜索好题。网上常有的方法是二进制判断,但我只会稍微剪枝而已。

对于此题已经足够了,换一种搜索方式,枚举剩下多少格子没有填。然后每次可以枚举一下判断下次该填那个格子。有一个贪心的思路就是每次枚举可填的数最少的格子。这样能有效减少状态分枝。

#include<bits/stdc++.h>
using namespace std;
int sudoku[150][150]; 
int score[10][10]{
    {0,0,0,0,0,0,0,0,0,0},
    {0,6,6,6,6,6,6,6,6,6},
    {0,6,7,7,7,7,7,7,7,6},
    {0,6,7,8,8,8,8,8,7,6},
    {0,6,7,8,9,9,9,8,7,6},
    {0,6,7,8,9,10,9,8,7,6},
    {0,6,7,8,9,9,9,8,7,6},
    {0,6,7,8,8,8,8,8,7,6},
    {0,6,7,7,7,7,7,7,7,6},
    {0,6,6,6,6,6,6,6,6,6}, 
};
int line[150][150];
int row[150][150];
int area[150][150];
long long maxx;
long long sum;
int tot;
void dfs(int rest,long long all){
    if(!rest){
        maxx=max(maxx,all);
        return;
    }
    int sss=19260817,xx,yy,step;
    for(int i=1;i<=9;i++){
        for(int j=1;j<=9;j++){
            if(!sudoku[i][j]){
                step=0;
                for(int k=1;k<=9;k++){
                    if(!line[j][k]&&!row[i][k]&&!area[(i-1)/3*3+(j-1)/3+1][k]) step++; 
                }
                if(step<sss){
                    sss=step;
                    xx=i;
                    yy=j;
                }
            }
        }
    }
    for(int i=1;i<=9;i++){
        if(!line[yy][i]&&!row[xx][i]&&!area[(xx-1)/3*3+(yy-1)/3+1][i]&&!sudoku[xx][yy]){
            line[yy][i]=true;
            row[xx][i]=true;
            area[(xx-1)/3*3+(yy-1)/3+1][i]=true;
            sudoku[xx][yy]=i;
            all+=sudoku[xx][yy]*score[xx][yy];
            dfs(rest-1,all);
            line[yy][i]=false;
            row[xx][i]=false;
            area[(xx-1)/3*3+(yy-1)/3+1][i]=false;
            all-=sudoku[xx][yy]*score[xx][yy];
            sudoku[xx][yy]=0;
        }
    }
}
int main(){
    maxx=-1;
    for(int i=1;i<=9;i++){
        for(int j=1;j<=9;j++){
            scanf("%d",&sudoku[i][j]);
            if(sudoku[i][j]){
                tot++;
                line[j][sudoku[i][j]]=true;
                row[i][sudoku[i][j]]=true;
                area[(i-1)/3*3+(j-1)/3+1][sudoku[i][j]]=true;
                sum+=score[i][j]*sudoku[i][j];
            }
        }
    } 
    dfs(81-tot,sum);//还有多少空格 
    printf("%d
",maxx);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/LJB666/p/11802644.html