Noip 2009 解题报告(潜伏着,Hankson的趣味题,最优贸易,靶形数独)

来源:互联网 发布:python win32api 编辑:程序博客网 时间:2024/06/05 13:22

校内赛,模拟Noip2009的题目。刚刚接到则个题目,我是很慌的。
不多说了直接正题。

由于题目被我搞掉了,所以只写解法吧。。。

第一题

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>using namespace std;const int N=100;const int M=26;char s1[N+5],s2[N+5],s3[N+5];int len1,len2,len3;int map[M+1];int main(){    freopen("spy.in","r",stdin);    freopen("spy.out","w",stdout);    memset(map,-1,sizeof(map));    scanf("%s",s1);    scanf("%s",s2);    scanf("%s",s3);    len1=strlen(s1),len2=strlen(s2),len3=strlen(s3);    for(int i=0;i<=len1-1;i++)    {        if(map[s1[i]-'A']!=-1&&map[s1[i]-'A']!=s2[i]-'A')        {            printf("Failed");            return 0;        }        map[s1[i]-'A']=s2[i]-'A';    }    for(int i=0;i<=24;i++)    for(int j=i+1;j<=25;j++)    if(map[i]==map[j])    {        printf("Failed");        return 0;    }    for(int i=0;i<=25;i++)    if(map[i]==-1)    {        printf("Failed");        return 0;    }    for(int i=0;i<=len3-1;i++)    printf("%c",map[s3[i]-'A']+'A');    return 0;}

这个就是我程序。好像过不完因为有点问题。。有一种情况无法判断。。将就看吧。

第二题

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>using namespace std;int n,a0,a1,b0,b1,ans;int gcd(int x,int y){    return y==0?x:gcd(y,x%y);}int lcm(int x,int y){    return x/gcd(x,y)*y;}bool judge(int x){    if(gcd(x,a0)!=a1)return 0;    if(lcm(x,b0)!=b1)return 0;    return 1;}int main(){    freopen("son.in","r",stdin);    freopen("son.out","w",stdout);    scanf("%d",&n);    while(n--)    {        int ans=0;        scanf("%d%d%d%d",&a0,&a1,&b0,&b1);        for(int i=1;i*i<=b1;i++)        {            if(b1%i==0)            {                if(judge(i)==1)ans++;                if(i*i!=b1) if(judge(b1/i)==1) ans++;            }        }        printf("%d\n",ans);    }    return 0;}

这道题就是普通的水题,但是注意只用循环到根号就可以。

第三题

这道题是我为数不多的能够AC得图论的题,其思路非常简洁明了:就是用两次广搜(或者说是SPFA)。第一次我们从头到尾更新出最小的点权,第二次我们从尾到头更新出最大的点权。再将路过每个点时所经过的最大最小点权的两个数组一一枚举,找到最大差值就可以了。

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>using namespace std;const int M=500000;const int N=100000;int n,m;int head1[N+5],head2[N+5],num=0;int w[N];int minn[N+5],maxn[N+5];struct edge{    int next1,next2,u,v;    edge(){next1=-1;next2=-1;}};struct edge ed[2*M+5];//临界表 void build(int u,int v){    num++;    ed[num].u=u;    ed[num].v=v;    ed[num].next1=head1[u];    head1[u]=num;    ed[num].next2=head2[v];    head2[v]=num;}//建表,相当于两张,分别是相反方向的两条路径 void bfs1(){    int front=0,rear=1;    int state[N],flag[N];    memset(flag,0,sizeof(flag));    memset(minn,0x7f,sizeof(minn));    state[rear]=1,minn[1]=w[1],flag[1]=1;    do    {        front++;        int u=state[front];        flag[u]=0;        for(int i=head1[u];i!=-1;i=ed[i].next1)        {            int v=ed[i].v;            if(minn[v]>minn[u]||w[v]<minn[v])            {                minn[v]=min(w[v],minn[u]);                if(flag[v]==0)state[++rear]=v;                flag[v]=1;            }        }    }while(front<rear);}//只要可以到达,就把最小的值赋成最小的值 void bfs2(){    int front=0,rear=1;    int state[N],flag[N];    memset(flag,0,sizeof(flag));    memset(maxn,-1,sizeof(maxn));    state[rear]=n,maxn[n]=w[n],flag[n]=1;    do    {        front++;        int u=state[front];             for(int i=head2[u];i!=-1;i=ed[i].next2)        {            int v=ed[i].u;            if(maxn[u]>maxn[v]||w[v]>maxn[v])            {                maxn[v]=max(w[v],maxn[u]);                if(flag[v]==0)state[++rear]=v;                flag[v]=1;            }        }        flag[u]=0;    }while(front<rear);}//只要可以到达,就把最大的值赋成最大的值, //但是是从n向起点1逆向寻找 int main(){    freopen("trade.in","r",stdin);    freopen("trade.out","w",stdout);    memset(head1,-1,sizeof(head1));    memset(head2,-1,sizeof(head2));    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)    scanf("%d",&w[i]);    for(int i=1;i<=m;i++)    {        int u,v,k;        scanf("%d%d%d",&u,&v,&k);        if(k==1)build(u,v);        if(k==2)        {            build(u,v);            build(v,u);        }    }//建表     bfs1();    bfs2();    int ans=0;    for(int i=1;i<=n;i++)    ans=max(ans,maxn[i]-minn[i]);//最大差值     printf("%d",ans);    return 0;}

第四题

原本想要深度优先搜索,结果发现代码有点复杂,而且不好处理。后来想到贪心,就是尽可能多的去填填的多的格子,发现自己又不太可能实现。但只用搜索的话注定会超时,所以我们还需要位运算。下面我们看一看大神的代码:

#include<iostream>#include<cstdlib>#include<cstdio>#include<algorithm>#include<iostream>#include<cmath>using namespace std;const int mlen=10;int a[mlen][mlen],b[mlen][mlen];int row[mlen],lie[mlen],line[mlen],ma[mlen];int f[512],ans,node[mlen],cnt[mlen];void init() {    for(int i=0;i<9;i++) b[i][0]=b[0][i]=b[8][i]=b[i][8]=6;    for(int i=1;i<8;i++) b[i][1]=b[1][i]=b[7][i]=b[i][7]=7;    for(int i=2;i<7;i++) b[i][2]=b[2][i]=b[6][i]=b[i][6]=8;    for(int i=3;i<6;i++) b[i][3]=b[3][i]=b[5][i]=b[i][5]=9;    b[4][4]=10; int t=0;    for(int i=1,j=0;i<=511;i<<=1,j++) f[i]=j;    for(int i=0;i<9;i++)        for(int j=0;j<9;j++)         {            scanf("%d",&a[i][j]);            if(a[i][j]!=0)            {                row[i]|=1<<j;                t=1<<(a[i][j]-1);                if((lie[i]&t)||(line[j]&t)||(ma[i/3*3+j/3]&t))                 {                    printf("-1\n");                     exit(0);                 }                lie[i]|=t;line[j]|=t;                ma[i/3*3+j/3]|=t;            }            else cnt[i]++;        }}void sore() {    int nowans=0;    for(int i=0;i<9;i++)     for(int j=0;j<9;j++)     nowans+=a[i][j]*b[i][j];    if(ans<nowans) ans=nowans;}//计算分数 void dfs(int t) {    int pos,k;    if(t==9)     {         sore();         return;     }    int i=node[t];    if(!cnt[i])     {         dfs(t+1);         return;     }    cnt[i]--;    int p=(511^row[i])&(-(511^row[i]));    row[i]|=p;    int j=f[p];    pos=511^(lie[i]|line[j]|ma[i/3*3+j/3]);    while(pos>0)     {        k=pos&(-pos);pos^=k;        lie[i]|=k;line[j]|=k;        ma[i/3*3+j/3]|=k;a[i][j]=f[k]+1;        dfs(t);        lie[i]^=k;line[j]^=k;        ma[i/3*3+j/3]^=k;    }    cnt[i]++;     row[i]^=p;}int main() {    freopen("sudoku.in","r",stdin);    freopen("sudoku.out","w",stdout);    init();    for (int i=0;i<9;i++)     node[i]=i;    for (int i=0;i<9;i++)    for (int j=i+1;j<9;j++)    if(cnt[node[i]]>cnt[node[j]]) node[i]^=node[j],node[j]^=node[i],node[i]^=node[j];    int tot=0;    while(!cnt[node[tot]]) tot++;    dfs(tot);    if(!ans)     {         printf("-1\n");         return 0;     }    printf("%d\n",ans);    return 0;}

至此,本次考试的总结就到这里。
2017 3 10

1 0
原创粉丝点击