zoukankan      html  css  js  c++  java
  • 【USACO2.2】解题报告

    前言

    在这里插入图片描述
    然而只有一道动态规划的题目。。。
    其他三道题都是模拟。。。
    难度还是有所增加的。至少在洛谷中又有一道蓝题了。
    USACO:http://train.usaco.org


    USACO2.2.3.Preface Numbering

    思路:
    我们会发现罗马数字中每一位都是独立的。不会遭到其他位的干扰。
    例如数字319731971132113271087108,他们的百位都是11,但是其他位没有一样的,但是百位的表示还都是不变的。
    那么就一位一位地处理,从高位到低位一个一个输出即可。


    代码:

    #include <cstdio>
    #include <iostream>
    using namespace std;
    
    const char ch[8]={' ','I','V','X','L','C','D','M'};
    const int num[8]={0,1,5,10,50,100,500,1000};
    int n,ans[8];
    
    void work(int x,int i)
    {
        if (x==1) ans[i*2-1]++;  //按位输出
        if (x==2) ans[i*2-1]+=2;
        if (x==3) ans[i*2-1]+=3;
        if (x==4) ans[i*2]++,ans[i*2-1]++;
        if (x==5) ans[i*2]++;
        if (x==6) ans[i*2]++,ans[i*2-1]++;
        if (x==7) ans[i*2]++,ans[i*2-1]+=2;
        if (x==8) ans[i*2]++,ans[i*2-1]+=3;
        if (x==9) ans[i*2+1]++,ans[i*2-1]++;
    }
    
    int main()
    {
        scanf("%d",&n);
        for (int j=1;j<=n;j++)
        {
            int x=j;
            for (int i=1;x;i++)
         	{
                work(x%10,i);  //一位一位输出
                x/=10;
            }
        } 
        for (int i=1;i<=8;i++)
         if (ans[i])
          cout<<ch[i]<<' '<<ans[i]<<endl;
        return 0;
    }
    

    USACO2.2.4.Subset Sums

    思路:
    很明显的DPDP啊。
    题目可以等价的转换为求在1n1sim n中选出几个数使得和为1+2+3+...+n2frac{1+2+3+ ... +n}{2}的方案数。
    很明显可以设f[i][j]f[i][j]表示选完ii个数,和为jj的方案数。那么就有
    f[i][j]+=f[i1][ji]f[i][j]+=f[i-1][j-i]
    那么答案就是f[n][1+2+3+...+n2]=f[n][n(1+n)22]=f[n][n(1+n)4]f[n][frac{1+2+3+ ... +n}{2}]=f[n][frac{frac{n(1+n)}{2}}{2}]=f[n][frac{n(1+n)}{4}]
    那么如果n(1+n)n(1+n)不是44的倍数就输出00好了。


    优化:
    可以利用背包的思想将第一位省略掉。


    代码:

    #include <cstdio>
    #define ll long long
    using namespace std;
    
    int n,m;
    ll f[1300];
    
    int main()
    {
        scanf("%d",&n);
        m=(n+1)*n/2;
        if (m%2) return !printf("0
    ");  //特判
        m/=2;
        f[0]=1;
        for (int i=1;i<=n;i++)
         for (int j=m;j>=i;j--)  //省略一维之后一定要倒序!
          f[j]+=f[j-i];
        printf("%lld
    ",f[m]/2);
        return 0;
    } 
    

    USACO2.2.5.Runaround Numbers

    思路:
    直接暴力模拟,每一个数判断一下即可。
    毫无难度。注意细节。


    代码:

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    
    int m,n,len,a[30];
    bool vis[30],ok;
    
    bool check()
    {
        memset(vis,0,sizeof(vis));
        int x=1;
        for (int i=1;i<=len;i++)
        {
            x=(x+a[x])%len;
            if (!x) x=len;
            if (vis[x]) return 0;  //不是回文数
            vis[x]=1;
        }
        return 1;
    }
    
    int main()
    {
        scanf("%d",&m);
        do
        {
            Continue:
            m++;
            n=m;
            len=0;
            ok=1;
            memset(vis,0,sizeof(vis));
            while (n)
            {
                a[++len]=n%10;
                if (vis[a[len]]) goto Continue;  //break诡异的出错了,所以选择了goto。但是建议少用goto!
                vis[a[len]]=1;
                n/=10;
            }
            for (int i=1;i<=len/2;i++)
             swap(a[i],a[len-i+1]);
        }
        while (!check());
        for (int i=1;i<=len;i++)
         printf("%d",a[i]);
        printf("
    ");
        return 0;
    }
    

    USACO2.2.6.Party Lamps

    思路:
    我们来看一下四种转化方法的循环结。

    1. 改变所有的数,循环结11
    2. 两个数中改变一个,循环结22
    3. 同上,循环结22
    4. 三个数中改一个,循环结33

    LCM(1,2,2,3)=6LCM(1,2,2,3)=6
    所以最终答案一定是每6个数为一个循环结
    那么我们就只要维护这个数列的前66个数就可以了!
    继续优化。
    我们知道,任意一种改变方式按奇数次和偶数次是相同的,即你按77次,101101次,798132565798132565次,2x+12x+1次都是一样的,而你按66次,198198次,354357752354357752次,2x2x次都是一样的。
    那么我们就对于每一种按钮枚举010sim1,表示按偶数下还是奇数下。那么如果满足:

    1. 所有的按钮按下后的奇偶性和总按下次数相同。
    2. 枚举的循环变量相加不大于总按下次数。

    那么就可以进行模拟,求出最终灯(的前六位),如果符合要求,就保存这个答案,最终排序输出即可。
    时间复杂度:O(1)O(1)(常数24×62^4 imes 6)。(或者说O(24×6)O(2^4 imes 6)


    代码:

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    int n,m,x,sum;
    bool o[7],c[7];
    
    struct answer
    {
        int num[7];
    }ans[30];
    
    bool cmp(answer x,answer y)  //从小到大排序
    {
        for (int i=1;i<=6;i++)
         if (x.num[i]<y.num[i]) return 1;
         else if (x.num[i]>y.num[i]) return 0;
        return 0;
    }
    
    bool check(int i,int j,int k,int l)
    {
    	//i^j^k^l表示最终的奇偶性,因为:
    	//0表示偶数,1表示奇数
    	//1^1=0,奇数+奇数=偶数
    	//0^0=0,偶数+偶数=偶数
    	//1^0=0^1=1,奇数+偶数=偶数+奇数=奇数
        return ((i^j^k^l)==(m&1))&&(i+j+k+l<=m);
    }
    
    void work(int i,int j,int k,int l)
    {
        int a[7]={1,1,1,1,1,1,1};
        if (i) 
         for (int q=1;q<=6;q++) a[q]^=1;
        if (j)
         for (int q=1;q<=6;q+=2) a[q]^=1;
        if (k)
         for (int q=2;q<=6;q+=2) a[q]^=1;
        if (l)
         for (int q=1;q<=6;q+=3) a[q]^=1;
        for (int q=1;q<=6;q++)
         if ((o[q]&&(!a[q]))||(c[q]&&a[q])) return;  //判断是否符合要求
        sum++;
        for (int q=1;q<=6;q++)
         ans[sum].num[q]=a[q];  //记录答案
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        while (1)
        {
            scanf("%d",&x);
            if (x==-1) break;
            o[(x-1)%6+1]=1;  //open,开着的灯
        }
        while (1)
        {
            scanf("%d",&x);
            if (x==-1) break;
            c[(x-1)%6+1]=1;  //close,关着的灯
        }
        for (int i=0;i<=1;i++)
         for (int j=0;j<=1;j++)
          for (int k=0;k<=1;k++)
           for (int l=0;l<=1;l++)
            if (check(i,j,k,l)) work(i,j,k,l);
        sort(ans+1,ans+1+sum,cmp);
        for (int i=1;i<=sum;i++)
        {
            for (int j=1;j<=n;j++)
         	 putchar(ans[i].num[(j-1)%6+1]+48);
         	printf("
    ");
        }
        if (!sum) puts("IMPOSSIBLE");
        return 0;
    }
    
  • 相关阅读:
    python学习 05 函数switch功能
    python学习 04 函数参数
    python学习 03 函数 (只会执行一次return就不会往下执行)
    【转】Jenkins+Ant+Jmeter接口自动化集成测试实例
    【转】python做一个http接口测试框架
    python学习 02 元组
    【转】使用 Python Mock 类进行单元测试
    【转】使用Python学习selenium测试工具
    【转】利用Python中的mock库对Python代码进行模拟测试
    【转】python测试开发面试题
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998464.html
Copyright © 2011-2022 走看看