• SRM 09


    A

      这道题就是要求删掉最右边若干本数之后,使得最终撕掉的书页最少。

      先按照P值从小到大排个序,然后先建立一个数组s[i],表示执行第i页的指令最远能撕到第几页(排序好之后的),由于P[i]是有序的,因此可以用二分查找。再用ans[i]表示若将i页之后的书页全部删去,最终会撕掉几页书,很显然ans[i]=ans[s[i]-1]+i-s[i],然后就不停地更新答案就行了。

    代码:

    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    #include<iostream>
    using namespace std;
    
    int p[1000],a[1000],s[1000],i,j,n,ans[1000],Ans=0x7fffffff;
    
    void qs(int l,int r)
    {
        int i=l,j=r,m=p[(l+r)>>1],t;
        while (i<=j)
        {
            while (p[i]<m) i++;
            while (p[j]>m) j--;
            if (i<=j)
            {
                t=p[i];p[i]=p[j];p[j]=t;
                t=a[i];a[i]=a[j];a[j]=t;
                i++;j--;
            }
        }
        if (i<r) qs(i,r);if (l<j) qs(l,j);
    }
    
    int Search(int k)
    {
        int m,l=1,r=n;
        while (l<=r)
        {
            m=(l+r)>>1;
            if (p[m]<k) l=m+1; else r=m-1; 
        }
        return l;
    }
    
    main()
    {
        scanf("%d",&n);
        for (i=1; i<=n; i++) scanf("%d%d",&p[i],&a[i]);
        qs(1,n);
        for (i=1; i<=n; i++)
        {
            s[i]=Search(p[i]-a[i]);
            ans[i]=ans[s[i]-1]+i-s[i];
            Ans=min(Ans,n-i+ans[i]);
        }
        printf("%d
    ",Ans);
    }
    A

    题目

    B

      给出两个数,一个是两数之和a,一个是两数异或之后的值b。

      由于异或是将两个数进行不进位的加法,因此设c=a-b为两数因为没有进位而造成的差,由于进位不可能在第一位,因此先将c右移一格。

      接着将b与c逐位转化为二进制,将每一位进行比较。若b[i]==1,c[i]==0,则表示这一位没有进位并且和为1,这样在这一位的情况有{1+0}{0+1},答案就*2;若b[i]==0,c[i]==1,则表示这一位有进位,所以在这一位只有{1+1}1种情况;若b[i]==0,c[i]==0则表示没有进位且和为0,只有{0+0}1种情况;若b[i]==1,c[i]==1,则不存在这样的情况,答案*0。

      最后特判一下若一开始a==b则ans-=2,因为题目要求是正整数,而这种情况下存在0+x和x+0的情况。

    代码:

    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define INF 0x7fffffff
    #define ll long long
    using namespace std;
    
    ll i,a,b,z[42],x[42],y[42],c,ans=1,l,r;
    
    main()
    {
        scanf("%lld%lld",&a,&b);
        c=(a-b)>>1;l=a;r=b;
        for (i=1; i<=41; i++) x[i]=c&1,c>>=1;
        for (i=1; i<=41; i++) y[i]=b&1,b>>=1;
        for (i=1; i<=41; i++)
        {
            if (x[i]==0 && y[i]==1) z[i]=2;
            if (x[i]==1 && y[i]==0) z[i]=1;
            if (x[i]==1 && y[i]==1) z[i]=0;
            if (x[i]==0 && y[i]==0) z[i]=1;
            ans*=z[i];
        }
        if (l==r) ans-=2;
         printf("%lld
    ",ans);
         return 0;
    }
    B

    题目

    C

      其实C的DP并不难写,考试的时候智障根本没想DP。

      设f[i][j]为撕掉[i,j]范围内的书最少要几步。于是先预处理,撕掉单一页的书只需要一步,因为单个字符就是一个回文串。然后就可以DP了。

      第一重枚举右端点j,第二重枚举左端点i,若a[i]==a[j]那当前的最小方案数就是f[i+1][j-1](这里要注意,当i+1==j时,f[i][j]=1;否则=f[i+1][j-1]);若不相同则赋值INF。接着不管f[i][j]是f[i+1][j-1]还是INF都交给下一重循环解决。设k由i枚举到j-1,在这个过程中不断更新f[i][j]的答案:f[i][j]=min(f[i][j],f[i][k]+f[k+1][j])。最终答案为f[1][n]。

    代码:

    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define INF 0x7fffffff
    using namespace std;
    
    int f[1000][1000],a[1000],i,j,k,n;
    
    main()
    {
        scanf("%d",&n);
        for (i=1; i<=n; i++) scanf("%d",&a[i]);
        for (i=1; i<=n; i++) f[i][i]=1;
        for (j=2; j<=n; j++)
        {
            for (i=j-1; i; i--)
            {
                if (a[i]==a[j])
                {
                    if (i+1==j) f[i][j]=1;
                    else f[i][j]=f[i+1][j-1];
                }
                else f[i][j]=INF;
                for (k=i; k<j; k++) f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
            }
        }
        printf("%d
    ",f[1][n]);
        return 0;
    }
    C

    题目

  • 相关阅读:
    C#的拓展方法
    敲代码
    获取GridView的rowdata
    C#为控件增加或删除委托
    ul嵌套ul IE7下空白行解决方案
    C#设置日期为指定的月份和日子
    web多选上传插件Uploadify
    如何通过key获取value值,键找值!多线程单利模式 3月15日第三版 希望各位路过的高手批评指正 给出更优秀的代码方便后来人
    IE条件语句,IE hack大全
    实现“记录用户登录时间和退出时间,同时记录用户IP,并且要记录用户IP对应的省和城市地址”
  • 原文地址:https://www.cnblogs.com/HAdolf-HQY/p/7288956.html
Copyright © 2020-2023  润新知