zoukankan      html  css  js  c++  java
  • NOIP2012提高组

    D1T1.Vigenère密码

    模拟

    #include<iostream> 
    #include<cstdio> 
    using namespace std; 
    int main() 
    { 
        string a,b;cin>>b>>a; 
        for(int i=0;i<a.size();i++) 
        { 
            bool ok=0;if(a[i]>='a'&&a[i]<='z')a[i]=a[i]-'a'+'A',ok=1;int j=i%b.size(); 
            if(b[j]>='a'&&b[j]<='z')b[j]=b[j]-'a'+'A'; 
            int c=((a[i]-'A')-(b[j]-'A')+26)%26;if(ok==0)cout<<(char)(c+'A');else cout<<(char)(c+'a'); 
        } 
        return 0; 
    } 
    View Code

    D1T2.国王游戏

    贪心+高精度

    我们知道,一个排序是经过好多次交换变成的,我们分析一下何时两个大臣需要交换,

    设第一个大臣左右手数字为(a1,b1),第二个大臣左手数字为(a2,b2),第一个大臣前面的所有大臣和国王左手数字的乘积为x

    那么交换前第一个大臣的奖赏为x/b1,第二个为(x*a1)/b2

    交换后第一个大臣为x/b2,第二个为(x*a2)/b1

    为了好看,我们设c1=x/b1,c2=(x*a1)/b2,c3=x/b2,c4=(x*a2)/b1

    因为a>=1,b>=1,所以c4>=c1,c2>=c3

    比较c2与c4的大小,可以发现,当a1/b2<a2/b1时,即a1*b1<a2*b2时,不交换是更优的,所以我们应该让a*b小的排在前面

    记得写高精度!!!!!!!!!!!!!!!!!

    #include<iostream>  
    #include<cstdio>  
    #include<cstring>  
    #include<algorithm>  
    using namespace std;  
    struct HP{  
        int s,n[10001];  
    }aa[1001];  
    struct xxx{  
        int a,b;  
    }x[1001];  
    bool cmp(xxx a,xxx b)  
    {  
        return a.a*a.b<b.a*b.b;  
    }  
    void Max(HP a,HP b,HP &c)  
    {  
        memset(c.n,0,sizeof(c.n));  
        if(a.s>b.s) c=a;  
        if(a.s<b.s) c=b;  
        if(a.s==b.s)  
        {  
            for(int i=a.s;i>=1;i--)  
            {  
                if(a.n[i]>b.n[i]){c=a;break;}  
                if(a.n[i]<b.n[i]){c=b;break;}  
            }  
            if(c.s==0)c=a;  
        }  
    }  
    void cheng(HP a,HP b,HP &c)  
    {  
        memset(c.n,0,sizeof(c.n));  
        for(int i=1;i<=a.s;i++)  
        for(int j=1;j<=b.s;j++)  
        {  
            c.n[i+j-1]+=(a.n[i]*b.n[j])%10000;  
            c.n[i+j]+=(a.n[i]*b.n[j])/10000;  
        }  
        if(c.n[a.s+b.s])c.s=a.s+b.s;  
        else c.s=a.s+b.s-1;  
    }  
    void chu(HP a,int b,HP &c)  
    {  
        memset(c.n,0,sizeof(c.n));  
        int now=0;  
        for(int i=a.s;i>=1;i--)  
        {  
            now+=a.n[i];c.n[i]=now/b;now=now%b*10000;  
        }  
        if(c.n[a.s])c.s=a.s;else c.s=a.s-1;  
    }  
    int main()  
    {  
        int n;scanf("%d",&n);for(int i=0;i<=n;i++)scanf("%d%d",&x[i].a,&x[i].b);  
        sort(x+1,x+n+1,cmp);  
        for(int i=0;i<=n;i++)aa[i].n[1]=x[i].a,aa[i].s=1;  
        HP MAX,tot=aa[0];chu(tot,x[1].b,MAX);cheng(tot,aa[1],tot);  
        for(int i=2;i<=n;i++)  
        {  
            HP v;chu(tot,x[i].b,v);Max(v,MAX,MAX);cheng(tot,aa[i],tot);  
        }  
        int d[5],dd=0;  
        while(MAX.n[MAX.s])  
        {  
            d[++dd]=MAX.n[MAX.s]%10;MAX.n[MAX.s]/=10;  
        }  
        for(;dd;dd--)printf("%d",d[dd]);  
        for(int i=MAX.s-1;i>=1;i--)printf("%04d",MAX.n[i]);  
        return 0;  
    }  
    View Code

     D1T3.开车旅行

    双向链表+倍增

    先用双向链表求出每个点的小A和小B能到达的点,具体做法如下:

    先排序,然后按数据在原数组的位置遍历,寻找每个数左边,左边的左边,右边,右边的右边的最小值和次小值

    找完一个数,删一个数。把每个点小A开一次,小B开一次,算作一次

    fa[i][j]表示从i点开2^j次到达的点,aa[i][j]表示从i点开2^j次小A开的距离,bb[i][j]表示从i点开2^j次小B开的距离

    fa[i][j]=fa[fa[i][j-1]][j-1];
    aa[i][j]=aa[i][j-1]+aa[fa[i][j-1]][j-1];
    bb[i][j]=bb[i][j-1]+bb[fa[i][j-1]][j-1];

    为了避免比值是double,所以a:b<c:d当ad<cb时,成立(c必须不等于0)

    最后,如果ansb一直是0的话,应输出海拔最高的

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int a[100011],b[100011],n,m,x[10011],s[10011],bh[100011];
    int fa[100011][20];long long aa[100011][20],bb[100011][20];
    struct xxx{
        int h,lnext,rnext,no;
    }data[100011];
    bool cmp(xxx a,xxx b){return a.h<b.h;}
    void gx(int _h,int _no,int h,int i,int &Min)
    {
        if(_h<=Min)
        {
            if(_h==Min)a[i]=_no;
            else {a[i]=b[i];Min=_h;b[i]=_no;}
        }
        else if(abs(h-data[bh[a[i]]].h)>_h)a[i]=_no;
    }
    void ab()
    {
        data[0].lnext=0;data[0].rnext=0;data[0].h=2000000003;
        for(int i=1;i<=n;i++)data[i].lnext=i-1,data[i].rnext=i+1;
        data[n].rnext=0;
        for(int i=1;i<=n;i++)
        {
            int Min=1000000001;
            int no=data[bh[i]].no,h=data[bh[i]].h,l=data[bh[i]].lnext,r=data[bh[i]].rnext;
            int l2h,l1h,r1h,r2h,l2no,l1no,r1no,r2no,l2,l1,r1,r2;
            l1=data[l].lnext;l2=data[l1].lnext;
            r1=data[r].rnext;r2=data[r1].rnext;
            l1h=data[l].h;l2h=data[l1].h;
            r1h=data[r].h;r2h=data[r1].h;
            l1no=data[l].no;l2no=data[l1].no;
            r1no=data[r].no;r2no=data[r1].no;
            if(l1)gx(h-l2h,l2no,h,i,Min);
            if(l)gx(h-l1h,l1no,h,i,Min);
            if(r)gx(r1h-h,r1no,h,i,Min);
            if(r1)gx(r2h-h,r2no,h,i,Min);
            if(l)data[l].rnext=r;if(r)data[r].lnext=l;
        }
    }
    void st()
    {
        for(int i=1;i<=n;i++)
        {
            if(a[i])aa[i][0]=abs(data[bh[i]].h-data[bh[a[i]]].h);
            if(b[a[i]])bb[i][0]=abs(data[bh[a[i]]].h-data[bh[b[a[i]]]].h);
            fa[i][0]=b[a[i]];
         } 
        for(int j=1;j<=16;j++)
        for(int i=1;i<=n;i++)
        {
            fa[i][j]=fa[fa[i][j-1]][j-1];
            aa[i][j]=aa[i][j-1]+aa[fa[i][j-1]][j-1];
            bb[i][j]=bb[i][j-1]+bb[fa[i][j-1]][j-1];
        }
    }
    void Ans(int u,int x,long long &ansa,long long &ansb)
    {
        for(int i=16;i>=0;i--)
        {
            if(fa[u][i]&&aa[u][i]+bb[u][i]<=x)
            {
                ansa+=aa[u][i],ansb+=bb[u][i];
                x=x-aa[u][i]-bb[u][i];u=fa[u][i];
            }
        }
        if(aa[u][0]<=x)ansa+=aa[u][0];
    }
    int main()
    {
        scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&data[i].h);data[i].no=i;}
        sort(data+1,data+n+1,cmp);for(int i=1;i<=n;i++)bh[data[i].no]=i;
        ab();st();int x;
        scanf("%d%d",&x,&m);
        long long ans=data[n].no,ansa=0ll,ansb=0ll;Ans(data[n].no,x,ansa,ansb);
        for(int i=n-1;i>=1;i--)
        {
            int u=data[i].no;
            long long aa=0ll,bb=0ll;Ans(u,x,aa,bb);
            if(ansa==0||aa*ansb<bb*ansa)ansa=aa,ansb=bb,ans=u;
        }
        if(ansb==0)ans=data[n].no;
        printf("%lld
    ",ans);
        for(int i=1;i<=m;i++)
        {
            int s,x;scanf("%d%d",&s,&x);
            long long aa=0ll,bb=0ll;Ans(s,x,aa,bb);
            printf("%lld %lld
    ",aa,bb);
        }
        return 0;
    }
    View Code

     D2T1.同余方程

    ax ≡ 1 (mod b)意味着ax-by==1,求x

    exgcd,ax-by==1可以看成ax+b(-y)==1

    #include<iostream> 
    #include<cmath> 
    using namespace std; 
    int x,y; 
    void gcd(int a,int b) 
    { 
        if(b==0){x=1;y=0;} 
        else
        { 
            gcd(b,a%b); 
            int t=x;x=y;y=t-a/b*y; 
        } 
    } 
    int main() 
    { 
        int a,b; 
        cin>>a>>b; 
        gcd(a,b); 
        x=(x%b+b)%b; 
        cout<<x; 
        return 0; 
    } 
    View Code

    D2T2.借教室

    二分+差分

    由于剩余的教室是非递增的,所以我们可以二分答案

    差分数组cf[]来差分r[]数组,cf[i]=r[i]-r[i-1]

    每次租借s到t的d间教室,只要cf[s]-=d;cf[t+1]+=d;即可

    然后还原原数组,如果剩余教室个数<0,就借不到这份订单,反之可以

    #include<iostream>  
    #include<cstdio>  
    #include<cstring>  
    using namespace std;  
    int cf[1000002],n,m,d[1000001],s[1000001],t[1000001],r[1000001];  
    bool check(int ans)  
    {  
        for(int i=1;i<=n+1;i++) 
        { 
            cf[i]=r[i]-r[i-1]; 
        } 
        for(int i=1;i<=ans;i++)  
        {  
            cf[s[i]]-=d[i];cf[t[i]+1]+=d[i];  
        }  
        int last=0;  
        for(int i=n;i>=1;i--)  
        {  
            int x=last-cf[i+1];last=x;if(x<0)return false;  
        } 
        return true;  
    }  
    int main()  
    {  
        scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%d",&r[i]);  
        for(int i=1;i<=m;i++)scanf("%d%d%d",&d[i],&s[i],&t[i]);  
        int l=1,r=m+1,ans=0;  
        while(l<r){  
            int mid=(l+r)/2;  
            if(check(mid))l=mid+1;  
            else ans=mid,r=mid;  
        }  
        if(ans==0)cout<<0;  
        else cout<<-1<<endl<<ans;  
        return 0;  
    }  
    View Code
  • 相关阅读:
    Windows 2003 服务器 关闭IIS中FTP匿名访问
    Linux 服务器 关闭FTP匿名访问
    CentOS 7 配置本地 YUM源
    Linux中使用MegaCli工具查看、管理Raid卡信息
    Linux 6 本地网络配置方法
    勒索病毒,华为/H3C三层交换机/路由器用ACL访问控制实现端口禁用
    Linux RedHat7.0_64位系统中安装Oracle_11g_R2
    Linux 7 重置root密码
    windows 系统防火墙 添加端口号方法
    SpringBoot 2.x (12):整合Elasticsearch
  • 原文地址:https://www.cnblogs.com/lher/p/6841786.html
Copyright © 2011-2022 走看看