• 2014-10-22 NOIP模拟赛


    1 1 、传教士 (bishop)

    问题描述:
    panzhili 王国的疆土恰好是一个矩形,为了管理方便,国王 jjs 将整个疆土划分成 N*
    M 块大小相同的区域。由于 jjs 希望他的子民也能信教爱教(”打拳”神教) ,所以他想安排一
    些传教士到全国各地去传教。 但这些传教士的传教形式非常怪异, 他们只在自己据点周围特
    定的区域内传教且领地意识极其强烈 (即任意一个传教士的据点都不能在其他传教士的传教
    区域内,否则就会发生冲突) 。现在我们知道传教士的传教区域为以其据点为中心的两条斜
    对角线上(如图) 。现在 jjs 请你帮忙找出一个合理的安置方案,使得可以在全国范围内安
    置尽可能多的传教士而又不至于任意两个传教士会发生冲突。
    X
    X X
    A
    X X
    (若 A 为某传教士的据点,则其传教范围为所有标有 X 的格子。为不产生冲突,则第
    二个传教士的据点只能放在上图的空格中。 )
    输入数据
    输入文件共一行,包含两个整数 N 和 M,代表国土的大小,n 为水平区域数,m 为垂
    直区域数。
    输出数据
    输出文件仅一行,包含一个整数,即最多可以安置的传教士的数目。
    样例输入 样例输入 bishop.in
    3 4
    样例输出 样例输出 bishop.out
    6
    说明:样例安置方案如下图所示,X 表示为某传教士的据点。
    XXX
    OOO
    OOO
    XXX
    对于 100%的数据,1<=n,m<=9,且数据规模呈梯度上升。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,m,ans;
    bool v1[30],v2[30];
    void dfs(int x,int y,int sum){
        ans=max(ans,sum);
        if(y>m||x>n)return;
        if(!v1[x-y+10]&&!v2[x+y]){
            v1[x-y+10]=1;
            v2[x+y]=1;
            if(y==m)dfs(x+1,1,sum+1);
            else dfs(x,y+1,sum+1);
            v1[x-y+10]=0;
            v2[x+y]=0;
        }
        if(y==m)dfs(x+1,1,sum);
        else dfs(x,y+1,sum);
    }
    int main(){
        freopen("bishop.in","r",stdin);
        freopen("bishop.out","w",stdout);
        scanf("%d%d",&n,&m);
        dfs(1,1,0);
        printf("%d",ans);
    }
    70分 暴力
    /*
        表打出来就很容易看出结论
        
        1 2 3 4 5 6 7
        2 2 4 4 6 6 8
        3 4 4 6 7 8 9
        4 4 6 6 8 8 10
        5 6 7 8 8 10 11
        6 6 8 8 10 10 12
        7 8 9 10 11 12 12
        
        奇偶列分类,然后n=m特判
    */
    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,m,ans;
    int main(){
        freopen("bishop.in","r",stdin);
        freopen("bishop.out","w",stdout);
        scanf("%d%d",&n,&m);
        if(n==1&&m==1){puts("1");return 0;}
        if(n>m)swap(n,m);
        if(n&1){
            ans=n+m-1;
            if(n==m)ans--;
        }
        else ans=n+(m-1)/2*2;
        printf("%d",ans);
        return 0;
    }
    100分 打表找规律

    2 、czy 把妹(czybm)

    Czy 是个大丧失,非常喜欢 bm。他经常挑战 bm 的极限,同时 b 很多的 mz。(虽然也
    许质量不容乐观)
    这一天,czy 又开始了他的极限挑战。在一个数轴上有 n 个 maze,她们都在等待着
    czy 的到来。Czy 一开始站在 k 号妹子的旁边,他需要搞定所有的妹子(由于他向 fewdan
    学会了绝技,所以搞定妹子的时间是无限接近于 0 的,也就是一瞬间就搞定而不用花额外
    的时间)。 Maze 们都很没有耐心, 每让她们多等 1s,她们就会增加 w[i]的不开心值。 现在,
    czy 从 k 号妹子这里出发,以 1m/s 的速度开始行动,他希望在搞定所有 maze 的情况下使
    得她们的不开心值总和最小,于是他找到了即将在 NOIP2014 AK 的你来帮他解决这个问
    题。
    文件输入:
    输入文件的第一行包含一个整数 N,2<=N<=1000,表示 maze 的数量。
    第二行包含一个整数 V,1<=V<=N,表示开始时 czy 站在几号 maze 的旁边.接下来的 N 行
    中,每行包含两个用空格隔开的整数 D 和 W,用来描述每个 maze,其中 0<=D<=1000,
    0<=W<=1000。D 表示 MM 在数轴上的位置(单位: m),W 表示每秒钟会增加的不开心值。
    文件输出:
    一个整数,最小的不开心值。(答案不超过 10^9)
    样例输入
    4
    3
    2 2
    5 8
    6 1
    8 7
    样例输出
    56
    对于 40%的数据,1<=n<=7
    对于 100%的数据,1<=n<=1000 0<=D<=1000 0<=w<=1000

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    using namespace std;
    #define maxn 1010
    int n,dis[maxn][maxn],s;
    long long ans=0x7fffffff;
    bool vis[maxn];
    struct node{
        int pos,w;
    }q[maxn];
    void dfs(int now,int cnt,long long sum,int tim){
        if(sum>=ans)return;
        if(cnt==n){
            if(sum<0)return;
            ans=min(ans,sum);
            return;
        }
        for(int i=1;i<=n;i++){//下一个要把的妹 
            if(!vis[i]){
                vis[i]=1;
                dfs(i,cnt+1,sum+q[i].w*(tim+dis[i][now]),tim+dis[i][now]);
                vis[i]=0;
            }
        }
    }
    int main(){
        //freopen("Cola.txt","r",stdin);
        freopen("czybm.in","r",stdin);
        freopen("czybm.out","w",stdout);
        scanf("%d%d",&n,&s);
        vis[s]=1;
        for(int i=1;i<=n;i++)
            scanf("%d%d",&q[i].pos,&q[i].w);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                dis[i][j]=abs(q[i].pos-q[j].pos);
        dfs(s,1,0,0);
        cout<<ans;
        return 0;
    }
    40分 暴力
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    int n,v,rp[1010],x[1010],sum[1010],l[1010][1010],r[1010][1010];
    int main(){
        freopen("czybm.in","r",stdin);
        freopen("czybm.out","w",stdout);
        int i,j,L;
        scanf("%d%d",&n,&v);
        for(i=1;i<=n;i++) scanf("%d%d",&x[i],&rp[i]);
        for(i=1;i<=n;i++) sum[i]=sum[i-1]+rp[i];
        for(i=1;i<=n;i++) r[i][i]=l[i][i]=abs(x[i]-x[v])*sum[n];
        for(L=2;L<=n;L++){
            for(i=1;i<=n;i++){
                j=i+L-1;  if(j>n) break;
                l[i][j]=l[i+1][j]+(x[i+1]-x[i])*(sum[i]+sum[n]-sum[j]);
                l[i][j]=min(l[i][j],r[i][j-1]+(x[j]-x[j-1])*(sum[i-1]+sum[n]-sum[j-1])+(x[j]-x[i])*(sum[n]-sum[j]+sum[i-1]));
                r[i][j]=r[i][j-1]+(x[j]-x[j-1])*(sum[i-1]+sum[n]-sum[j-1]);
                r[i][j]=min(r[i][j],l[i+1][j]+(x[i+1]-x[i])*(sum[i]+sum[n]-sum[j])+(x[j]-x[i])*(sum[i-1]+sum[n]-sum[j]));
            }
        }
        printf("%d
    ",min(l[1][n],r[1][n]));
        return 0;
    }
    100分 dp

    3、hzwer的跳跳棋(hop)

    【问题描述】

    Hzwer的跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。

    某一天,黄金大神和cjy用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置。他们要通过最少的跳动把它们的位置移动成x,y,z。(棋子是没有区别的)

    跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。

     

    写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。

    【输入格式】

    第一行包含三个整数,表示当前棋子的位置a b c。(互不相同)

    第二行包含三个整数,表示目标位置x y z。(互不相同)

    【输出格式】

    如果无解,输出一行NO。

    如果可以到达,第一行输出YES,第二行输出最少步数。

    【样例输入】

    1 2 3

    0 3 5

    【样例输出】

    YES

    2

    【范围】

    20% 输入整数的绝对值均不超过10

    40% 输入整数的绝对值均不超过10000

    100% 绝对值不超过10^9

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<algorithm> 
    #include<cmath>
    #include<cstdlib>
    using namespace std;
    #define mod1 23333333
    #define mod2 45975231
    int s1,s2,s3,t1,t2,t3;
    bool vis[23333334];
    struct node{
        int a,b,c,step;
    }cur,nxt;
    int hash(int a,int b,int c){
        int a1=1LL*(a+1000000000)*456%mod2;
        int a2=1LL*(b+1000000000)*32%mod2;
        int a3=1LL*(c+1000000000)*147%mod2;
        int res=(1LL*a1*a2%mod1)*a3%mod1;
        return res;
    }
    queue<node>q;
    void push(int a,int b,int c,int step){
        node now;
        now.a=a;now.b=b;now.c=c;now.step=step;
        q.push(now);
        vis[hash(a,b,c)]=1;
        vis[hash(a,c,b)]=1;
        vis[hash(b,a,c)]=1;
        vis[hash(b,c,a)]=1;
        vis[hash(c,a,b)]=1;
        vis[hash(c,b,a)]=1;
    }
    bool pan(int a,int b,int c){
        if(a==t1&&b==t2&&c==t3)return 1;
        if(a==t1&&b==t3&&c==t2)return 1;
        if(a==t2&&b==t1&&c==t3)return 1;
        if(a==t2&&b==t3&&c==t1)return 1;
        if(a==t3&&b==t1&&c==t2)return 1;
        if(a==t3&&b==t2&&c==t1)return 1;
        return 0;
    }
    int z[5];
    int bfs(){
        while(!q.empty()){
            node now=q.front();q.pop();
            int s=now.step;
            z[1]=now.a,z[2]=now.b,z[3]=now.c;
            sort(z+1,z+4);
            int a,b,c;
            int dis;
            
            a=z[1],b=z[1]-(z[2]-z[1]),c=z[3];
            if(pan(a,b,c))return s+1;
            if(!vis[hash(a,b,c)])push(a,b,c,s+1);
            
            a=z[1],b=z[3]+(z[3]-z[2]),c=z[3];
            if(pan(a,b,c))return s+1;
            if(!vis[hash(a,b,c)])push(a,b,c,s+1);
            
            if(z[2]-z[1]>z[3]-z[2]){
                a=z[1],b=z[2]-(z[3]-z[2]),c=z[2];
                if(pan(a,b,c))return s+1;
                if(!vis[hash(a,b,c)])push(a,b,c,s+1);
            }
            if(z[2]-z[1]<z[3]-z[2]){
                a=z[2],b=z[2]+(z[2]-z[1]),c=z[3];
                if(pan(a,b,c))return s+1;
                if(!vis[hash(a,b,c)])push(a,b,c,s+1);
            }
        }
        return -1;
    }
    int main(){
        //freopen("Cola.txt","r",stdin);
        freopen("hop.in","r",stdin);
        freopen("hop.out","w",stdout);
        scanf("%d%d%d%d%d%d",&s1,&s2,&s3,&t1,&t2,&t3);
        push(s1,s2,s3,0);
        int ans=bfs();
        if(ans==-1){
            printf("NO");return 0;
        }
        else {
            printf("YES
    %d",ans);
            return 0;
        }
    }
    15分 暴力
    /*
        对于一个状态,中间的一个棋子可以往两边跳,而两边的棋子最多只有一个可以往中间跳
        故每个状态看做一个点,有关连的状态连起来,就形成了一棵二叉树
        对于一个某个有解的状态而言,中间往两边跳的两个状态是它的儿子,两边往中间跳的状态是它的父亲
        于是就变成了树上两点求距离问题。
        暴力只有40分
        若记前两个数差t1,后两个数差t2,不妨设t1<t2则左边最多往中间跳(t2-1)/t1次然后只能右边往中间跳,是一个辗转相除的过程,即在logK的时间内我们可以用这种方法得到某个结点它向上K次后的结点,或者根节点,同时还可以顺便算下深度
        于是就变成了先把两个节点调到树上同一深度再二分LCA的深度即可
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int INF=(int)1e9;
    struct data{
        int a[4];
        bool operator != (const data b){
            return (a[1]!=b.a[1]||a[2]!=b.a[2]||a[3]!=b.a[3]);
        }
    };
    int t1,t2,tmp,ans;
    int a[4],b[4];
    
    data calc(int *a,int k){
        data res;
        int t1=a[2]-a[1],t2=a[3]-a[2],t;
        for(int i=1;i<4;i++)res.a[i]=a[i];
        if(t1==t2)return res;
        if(t1<t2){
            t=min(k,(t2-1)/t1);
            k-=t,tmp+=t;
            res.a[2]+=t*t1,res.a[1]+=t*t1;
        }
        else {
            t=min(k,(t1-1)/t2);
            k-=t,tmp+=t;
            res.a[2]-=t*t2,res.a[3]-=t*t2;
        }
        return k?calc(res.a,k):res;
    }
    
    int main(){
        freopen("hop.in","r",stdin);
        freopen("hop.out","w",stdout);
        int d1,d2;
        data t1,t2;
        for(int i=1;i<4;i++)scanf("%d",&a[i]);
        for(int i=1;i<4;i++)scanf("%d",&b[i]);
        sort(a+1,a+4);
        sort(b+1,b+4);
        t1=calc(a,INF),d1=tmp,tmp=0;
        t2=calc(b,INF),d2=tmp,tmp=0;
        if(t1!=t2){
            printf("NO");
            return 0;
        }
        if(d1>d2){
            swap(d1,d2);
            for(int i=1;i<4;i++)swap(a[i],b[i]);
        }
        ans=d2-d1;
        t1=calc(b,ans);
        for(int i=1;i<4;i++)b[i]=t1.a[i];
        int l=0,r=d1,mid;
        while(l<=r){
            mid=l+r>>1;
            if(calc(a,mid)!=calc(b,mid))l=mid+1;
            else r=mid-1;
        }
        printf("YES
    %d",ans+2*l);
        return 0;
    }
    100分 lca+二分
  • 相关阅读:
    一道编程题: 在1~n之间选择若干个数,使其和为m
    关于raft算法
    程序员算法基础——动态规划
    c++中两个类互相引用的问题
    c++ 之模板进阶
    jmeter分布式操作-远程启动功能探索
    linux下安装不同版本的jdk
    Jmeter插件监控服务器性能
    测试开发面试-技术持续累积
    python:Jpype安装和使用
  • 原文地址:https://www.cnblogs.com/thmyl/p/7488070.html
Copyright © 2020-2023  润新知