zoukankan      html  css  js  c++  java
  • NOIP摩尼赛(或许普及难度?)

    考前日常。。。

    1、某种密码(password.*)

        关于某种密码有如下描述:某种密码的原文A是由N个数字组成,而密文B是一个长度为N的01数串,原文和密文的关联在于一个钥匙码KEY。若KEY=∑▒〖Ai*Bi〗,则密文就是原文的一组合法密码。

             现在有原文和钥匙码,请编一个程序来帮助他统计到底有多少个符合条件的密文。

    【输入数据】

             第一行两个数N,KEY,意义同题目描述;

             第二行N个数表示原文A,意义同题目描述。

    【输出数据】

             一个数ANS,表示对于原文A和KEY,有多少组可行的密文B。

    【输入样例】

    3 2

    1 1 2

    【输出样例】

    2

    【样例说明】

    密文110,1*1+1*1+0*2=2

    密文001,0*1+0*1+1*2=2

    一共两组可行的密文。

    【数据约定】

    60%数据满足N<=25

    100%数据满足N<=40,-maxlongint<=∑▒Ai<=maxlongint


    初看觉水;

    思路历程:搜索(2^n ???)----》背包(maxint???)---》背包+hash(n的大小不允许我这样做)---》折半搜索+hash桶计(海星)

    没什么说的了,下面是CPP

    #include<bits/stdc++.h>
    using namespace std;
    //long long bao1[1200000],bao2[1200000];
    int n,N;
    long long a[50],key,ji1=0;
    map<long long,int>hash;
    inline void dfs1(int pos,long long sum)
    {
    //    if(sum>key)return ;
        if(pos==N)
        {
    //        bao1[++ji1]=sum;
    //        bao1[++ji2]=sum+a[pos];
            hash[sum]++;hash[sum+a[pos]]++;
            return ;
        }
        dfs1(pos+1,sum+a[pos]);
        dfs1(pos+1,sum);
    } 
    inline void dfs2(int pos,long long sum)
    {
    //    if(sum>key)return ;
        if(pos==n)
        {
    //        bao2[++ji2]=sum;
    //        bao2[++ji2]=sum+a[pos];
            ji1+=hash[key-sum];ji1+=hash[key-sum-a[pos]];
            return ;
        }
        dfs2(pos+1,sum+a[pos]);
        dfs2(pos+1,sum);
    }
    
    int main()
    {
    //    freopen("DDD.in","r",stdin);
        scanf("%d%lld",&n,&key);
        for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
    //    sort(a+1,a+n+1);
        N=n/2;
        dfs1(1,0);
        dfs2(N+1,0);
    //    int ji1=(1<<N),ji2=(1<<(n-N-1));
    //    for(int i=1;i<=ji1;++i)
    //    {
    //        map[bao1[i]]++;
    //    } 
    //    sort(bao1+1,bao1+ji1+1);
    //    sort(bao2+1,bao2+ji2+1,PP);
    //    int j=ji2,ans=0;
    //    for(int i=1;i<=ji1;++i)
    //    {
    //        bool fla=0;
    //        while(bao1[i]+bao2[j]>key)
    //        {
    //            j--;
    //        }
    //        while(bao1[i]+bao2[j]==key)
    //        {
    //            ans++;i++;j--;fla=1;
    //        }
    //        if(fla)i--;
    //    }
        printf("%lld",ji1);
        return 0;
    }
    /*
    40 5
    1 1 1 1 1 1 1 1 1 1
    1 1 1 1 1 1 1 1 1 1
    1 1 1 1 1 1 1 1 1 1
    1 1 1 1 1 1 1 1 1 1
    */

    注释的地方有一些剪枝,当然加了会有红紫;


    2、球的序列(formation.*)

       N个编号为1-n的球,每个球都有唯一的编号。这些球被排成两种序列,分别为A、B序列,现在需要重新寻找一个球的序列l,对于这个子序列l中任意的两个球,要求j,k(j<k),都要求满足lj在A中位置比lk在A中位置靠前,且lj在B中位置比lk在B中位置靠前,请你计算这个子序列l的最大长度。

    输入:

    第一行一个整数,表示N。

    第二行N个整数,表示A序列。

    第三行N个整数,表示B序列。

    样例输入

    5

    1 2 4 3 5

    5 2 3 4 1

    样例输出

    2

    样例说明

    L可以是{2,3},也可以是{2,4}

    数据范围:

    40% N<=5000

    100% N<=50000


    依旧是水的;

    分吸分吸:如果对 Lj,Lk( j<k ) 有  ALj  在 ALk  前,且B Lj  在 B Lk 前;那么Lj,Lk 在A,B中相对位置不变;即LCS;

    nlogn求:

    #include<bits/stdc++.h>
    using namespace std;
    int read()
    {
        int x,f=0;char ch=getchar();
        while(!isdigit(ch)){f=1;ch=getchar();}
        while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        return f?-x:x; 
    }
    int f[50100],A[50100],B[50100],ma[50100],mb[50100],len,n;
    int che(int x)
    {
        int l=0,r=len+1,mid;
        while(l<r)
        {
            mid=((l+r)>>1);
            if(f[mid]>=x)
            {
                r=mid;
            }
            else
            {
                l=mid+1;
            }
        }
        return l;
    }
    int main()
    {
    //    n=read();
    //    for(int i=1;i<=n;++i)
    //    {    A[i]=read();    ma[A[i]]=i;    }
    //    for(int i=1;i<=n;++i)
    //    {    B[i]=read();    mb[i]=ma[B[i]];    }
        freopen("formation.in","r",stdin);
        freopen("formation.out","w",stdout);
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&A[i]);ma[A[i]]=i;
        }
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&B[i]);mb[i]=ma[B[i]];
        }
        f[1]=mb[1];
        len=1;
        for(int i=2;i<=n;++i)
        {
            if(mb[i]>f[len])
            {
                len++;f[len]=mb[i];
            }
            else
            {
                int pos=che(mb[i]);
                f[pos]=mb[i];
            }
        }
        printf("%d",len);
        return 0;
     } 

    3大逃亡(escape.*)

    给出数字N(1<=N<=10000),X(1<=x<=1000),Y(1<=Y<=1000),代表有N个敌人分布一个X行Y列的矩阵上,矩形的行号从0到X-1,列号从0到Y-1再给出四个数字x1,y1,x2,y2,代表你要从点(x1,y1)移到(x2,y2)。在移动的过程中你当然希望离敌人的距离的最小值最大化,现在请求出这个值最大可以为多少,以及在这个前提下,你最少要走多少步才可以回到目标点。注意这里距离的定义为两点的曼哈顿距离,即某两个点的坐标分为(a,b),(c,d),那么它们的距离为|a-c|+|b-d|。

    输入:

    第一行给出数字N,X,Y

    第二行给出x1,y1,x2,y2

    下面将有N行,给出N个敌人所在的坐标

    输出:

    在一行内输出你离敌人的距离及在这个距离的限制下,你回到目标点最少要移动多少步。

    Sample input

    2 5 6

    0 0 4 0

    2 1

    2 3

    Sample output

    2 14


    题意在明示二分与敌人最小距离......;

    1st:floodfill(BFS)处理每个点与最近敌人的距离;

    2nd:二分与敌人最小距离再BFS寻终点;

    时间:O(log(n+m)*(n+m)+n+m)(当然是口胡了)

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    using namespace std;
    bool mark[1010][1010];
    int map[1010][1010];
    int x[5000010],y[5000010];
    int bs[1010][1010];
    int n,m,k,tou,wei,qx,qy,zx,zy;
    int dx[4]={0,0,1,-1};
    int dy[4]={1,-1,0,0};
    void init()
    {
        int i,a,b;
        scanf("%d%d%d",&k,&n,&m);
        tou=1;wei=0;
        scanf("%d%d%d%d",&qx,&qy,&zx,&zy);
        qx++;qy++;zx++;zy++;
        for(i=1;i<=k;i++)
        {
            scanf("%d%d",&a,&b);
            a++;b++;
            wei++;x[wei]=a;y[wei]=b;
            mark[a][b]=1;
        }
    }
    void bfs()
    {
        int i,nx,ny,xx,yy,p;
        while(tou<=wei)
        {
            xx=x[tou];yy=y[tou];tou++;
            for(p=0;p<4;p++)
            {
                nx=xx+dx[p];ny=yy+dy[p];
                if(nx<1 || nx>n || ny<1 || ny>m)   continue;
                if(!mark[nx][ny])
                {
                    mark[nx][ny]=1;map[nx][ny]=map[xx][yy]+1;
                    wei++;x[wei]=nx;y[wei]=ny;
                }
            }    
        }
    }
    bool check(int mid)
    {
        int i,xx,yy,nx,ny,p;
        tou=1;wei=1;x[1]=qx;y[1]=qy;
        memset(mark,0,sizeof(mark));
        memset(bs,127,sizeof(bs));
        mark[qx][qy]=1;bs[qx][qy]=0;
        while(tou<=wei)
        {
            xx=x[tou];yy=y[tou];tou++;
            for(p=0;p<4;p++)
            {
                nx=xx+dx[p];ny=yy+dy[p];
                if(nx<1 || nx>n || ny<1 || ny>m || map[nx][ny]<mid)   continue;
                if(!mark[nx][ny])
                {
                    mark[nx][ny]=1;bs[nx][ny]=bs[xx][yy]+1;
                    wei++;x[wei]=nx;y[wei]=ny;
                }
            }
        }
        if(mark[zx][zy])  return 1;
        else return 0;
    }
    int main()
    {
        freopen("escape.in","r",stdin);
        freopen("escape.out","w",stdout);
        init();
        bfs();
        int l=0,r=map[qx][qy],mid;
        while(l+1<r)
        {
            mid=(l+r)>>1;
            if(check(mid))  l=mid;
            else r=mid;
        }
        if(check(r)) 
        {cout<<r<<" "<<bs[zx][zy]<<endl;}
        else
        {check(l);cout<<l<<" "<<bs[zx][zy]<<endl;}
    //    system("pause");
        return 0;
    }

    如果真爱有颜色,那么一定是红橙黄紫深蓝吧;

     

  • 相关阅读:
    Python模块time、datetime
    Python装饰器、内置函数之金兰契友
    Python生成器、推导式之前襟后裾
    Python函数二(函数名,闭包,迭代器)之杵臼之交
    Python函数(一)之杵臼之交
    katalon系列二:selenium IDE的替代者——Katalon Recorder
    katalon系列一:初识Katalon Studio自动化测试工具
    windows下使用RoboCopy命令进行文件夹增量备份
    Selenium+Python自动化之如何绕过登录验证码
    UI自动化录制工具----UI Recorder
  • 原文地址:https://www.cnblogs.com/hjk-biu/p/9743755.html
Copyright © 2011-2022 走看看