下午队内pk,崔ghostplant惊心设计了一道背包,时间复杂度是O(n*m),10e7能过10e8不能过,时间复杂度卡的非常好,不少人都tle了,突然raya发现贪心也能过,结果我们房间几个人全部猥琐贪心过了,我46ms,而dp的在1200ms-2500ms之间,题目3s。
比赛结束后,我打开测试数据,发现太水了,只有25组,其实只有5组不同的,剩下的都死卡时间的。


我改了一下测试数据,让所有贪心的都wa了,结果zlly和huangc的dp也wa了,哈哈,第一次玩judge,太有趣了!


题目:求1+2+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句(A?B:C)。

分析:这道题没有多少实际意义,因为在软件开发中不会有这么变态的限制。但这道题却能有效地考查发散思维能力,而发散思维能力能反映出对编程相关技术理解的深刻程度。

通常求1+2+…+n除了用公式n(n+1)/2之外,无外乎循环和递归两种思路。由于已经明确限制for和while的使用,循环已经不能再用了。同样,递归函数也需要用if语句或者条件判断语句来判断是继续递归下去还是终止递归,但现在题目已经不允许使用这两种语句了。

我们仍然围绕循环做文章。循环只是让相同的代码执行n遍而已,我们完全可以不用for和while达到这个效果。比如定义一个类,我们new一含有n个这种类型元素的数组,那么该类的构造函数将确定会被调用n次。我们可以将需要执行的代码放到构造函数里。如下代码正是基于这个思路:

class Temp
{
public:
      Temp() { ++ N; Sum += N; }

      static void Reset() { N = 0; Sum = 0; }
      static int GetSum() { return Sum; }

private:
      static int N;
      static int Sum;
};

int Temp::N = 0;
int Temp::Sum = 0;

int solution1_Sum(int n)
{
      Temp::Reset();

      Temp *a = new Temp[n];
      delete []a;
      a = 0;

      return Temp::GetSum();
}

我们同样也可以围绕递归做文章。既然不能判断是不是应该终止递归,我们不妨定义两个函数。一个函数充当递归函数的角色,另一个函数处理终止递归的情况,我们需要做的就是在两个函数里二选一。从二选一我们很自然的想到布尔变量,比如ture(1)的时候调用第一个函数,false(0)的时候调用第二个函数。那现在的问题是如和把数值变量n转换成布尔值。如果对n连续做两次反运算,即!!n,那么非零的n转换为true,0转换为false。有了上述分析,我们再来看下面的代码:

class A;
A* Array[2];

class A
{
public:
      virtual int Sum (int n) { return 0; }
};

class B: public A
{
public:
      virtual int Sum (int n) { return Array[!!n]->Sum(n-1)+n; }
};

int solution2_Sum(int n)
{
      A a;
      B b;
      Array[0] = &a;
      Array[1] = &b;

      int value = Array[1]->Sum(n);

      return value;
}

这种方法是用虚函数来实现函数的选择。当n不为零时,执行函数B::Sum;当n为0时,执行A::Sum。我们也可以直接用函数指针数组,这样可能还更直接一些:

typedef int (*fun)(int);

int solution3_f1(int i)
{
      return 0;
}

int solution3_f2(int i)
{
      fun f[2]={solution3_f1, solution3_f2};
      return i+f[!!i](i-1);
}

另外我们还可以让编译器帮我们来完成类似于递归的运算,比如如下代码:

template <int n> struct solution4_Sum
{
      enum Value { N = solution4_Sum<n - 1>::N + n};
};

template <> struct solution4_Sum<1>
{
      enum Value { N = 1};
};

solution4_Sum<100>::N就是1+2+...+100的结果。当编译器看到solution4_Sum<100>时,就是为模板类solution4_Sum以参数100生成该类型的代码。但以100为参数的类型需要得到以99为参数的类型,因为solution4_Sum<100>::N=solution4_Sum<99>::N+100。这个过程会递归一直到参数为1的类型,由于该类型已经显式定义,编译器无需生成,递归编译到此结束。由于这个过程是在编译过程中完成的,因此要求输入n必须是在编译期间就能确定,不能动态输入。这是该方法最大的缺点。而且编译器对递归编译代码的递归深度是有限制的,也就是要求n不能太大。

大家还有更多、更巧妙的思路吗?欢迎讨论^_^

博主何海涛对本博客文章享有版权。网络转载请注明出处http://zhedahht.blog.163.com/。整理出版物请和作者联系。

最后附上一个简单的代码:

#include <iostream>

int add(int n, int &sum)

{

   n && add(n-1, sum);

   return sum += n;

}

int main()

{

   int sum = 0;

   int n = 100;

   std::cout << add(n, sum) << std::endl;return 0;

}


顶嵌杯用这个就能AC:

第一题:

main(){puts("5*(5-(1/5))");}

第二题:
main(){puts("(0, 0)\n(1, 0)\n(2, 0)\n(2, 1)\n(2, 2)\n(2, 3)\n(2, 4)\n(3, 4)\n(4, 4)");}

仔细一看就知道其实就是题目给的测试数据
我知道什么叫顶嵌了 就是把答案嵌入进去?顶嵌杯是世界上最假的比赛 - 橙衣少年 - 跟着我勇敢地走下去

ps:zlly打了一个很大的表(10以内所有的计算24公式),测试数据没过,遂放弃?顶嵌杯是世界上最假的比赛 - 橙衣少年 - 跟着我勇敢地走下去


顶嵌杯决赛第二题,简单的bfs,关键是gcc不能用stl,所以得自己写一个队列。

已注释:

#include <stdio.h>
#include <stdlib.h>
int mm[5][5];
int dir[4][2]={ {0,1},{0,-1},{1,0},{-1,0}};

typedef struct
{
int x,y;//坐标
int pre;//前一节点
}node ;

node que[10005];
int vs[5][5];//标记已访问


int judge(node a)
{
if(a.x<0||a.y<0||a.x>=5||a.y>=5)return 0; //越界返回0
if(mm[a.x][a.y]==1)return 0;//墙
return 1;
}


void dfs(node a)//这个其实是输出输出函数
{
if(a.pre==-1)return ;//结束条件(找到原点)
else dfs(que[a.pre]);
printf("(%d, %d)\n",a.x,a.y);//从第二个节点开始顺序输出,注意中间有个空格
}


int work()//广搜函数
{
int i;
node t1,t2;
memset(vs,0,sizeof(vs));//这个其实无所谓的吧
int sp,head;//sp队尾标志,head队首标志
//初始化左上角
que[0].x=0;
que[0].y=0;
que[0].pre=-1;
vs[0][0]=1;
head=0;
sp=1;
while(head<sp)
{
   t1=que[head];//队首出队
   head++;//对手标记加1
   if(t1.x==4&&t1.y==4)break;//已找到,退出
   t2=t1;
   for(i=0;i<4;i++)//遍历四个方向
   {
    t2.x+=dir[i][0];
    t2.y+=dir[i][1];
    if(judge(t2) && vs[t2.x][t2.y]==0)//vs是已访问
    {
     t2.pre=head-1;//标记前节点(在que里的序号)
     que[sp++]=t2;//进队
     vs[t2.x][t2.y]=1;//标记已访问
    }
   }
}
dfs(t1);
return 0;
}
int main ()
{
int i,j;
for(i=0;i<5;i++)
{
   for(j=0;j<5;j++)scanf("%d",&mm[i][j]);
  
}
printf("(0, 0)\n");
work();
return 0;
}


CUGB第四届程序设计大赛解题报告
比赛链接:
http://acm.cugb.edu.cn/JudgeOnline/showcontest?contest_id=1038
A题   医院的灯

水题,只有4盏灯,1到4查找灯的状态,遇到1(明)就输出再break;如果查

找到4还是0(暗)的状态,就输出-1

我没考虑-1WA了一次,然后没改Main CE了一次,一不小心一个小时就没了,

郁闷!

代码:
import java.io.*;
import java.util.*;

public class a {
public static void main(String args[]) {
   int a,b,c,d;
   Scanner cin = new Scanner(new BufferedInputStream

(System.in));
   while(cin.hasNext()) {
    a=cin.nextInt();
    b=cin.nextInt();
    c=cin.nextInt();
    d=cin.nextInt();
    if(a==1) {

     System.out.println("L1");
     continue;
    }
    if(b==1) {

     System.out.println("L2");
     continue;
    }
    if(c==1) {

     System.out.println("L3");
     continue;
    }
    if(d==1) {

     System.out.println("L4");
     continue;
    }
    System.out.println ("-1");
   }
}
}

B题: 僵尸农场大致是给你N*N块土地的状态,然后统计金币总额,注意:这里

只有植物(或者僵尸)为"ripe"的状态下,才把金币加上去,同时先假设心情

为高兴(flag=0),如果遇见状态为"withered", 则f=1;

import java.io.*;
import java.util.*;
import java.math.*;

public class b {
public static void main(String args[]) {

   int a,b,c,d,flag,money,i;
   String s;
   BigInteger x;
   Scanner cin = new Scanner(new BufferedInputStream

(System.in));
   while(cin.hasNext()) {
    a=cin.nextInt();
    money=0;
    flag=0;
    for(i=0; i<a*a; i++) {
     s=cin.next();
     if(s.equals("None")) {


     } else if(s.equals("Plant") ||

s.equals("Zombie")) {
      s=cin.next();
      if(s.equals("growing")) {
       b=cin.nextInt();
      } else if(s.equals("ripe"))

{
       b=cin.nextInt();
       money+=b;

      } else if(s.equals

("withered")) {
       b=cin.nextInt();
       flag=1;
      }
     }

    }

    if(flag==0)
     System.out.println("DSHAN is happy

and she has just earned "+money+" Gold.");
    else
     System.out.println("DSHAN is

depressed and she has just earned "+money+" Gold.");
   }
}

}

C题:wildfire很水,用set stl,自带排序去重功能,再用set迭代器输出
因为我不会java的stl,所以用c++写

#include<cstdio>
#include<iostream>
#include<set>
using namespace std;
int main(){
unsigned int t,tt;
int a;
while(scanf("%d",&t)!=EOF)
{
   set<int> s;
   for(tt=0;tt<t;tt++)
   //while(t--)
   {
    scanf("%d",&a);
    s.insert(a);
   }
   printf("%d\n",s.size());
   set<int>::iterator it;//定义前向迭代容器
   it=s.begin();
   cout<<*it;
   for(it=++s.begin();it!=s.end();it++)
   {
    cout<<" "<<*it;
   }
cout<<endl;
}
    return 0;
}

D题:(哈尔滨现场赛的题目)贪心算法,排序,正逆相加即可

#include<iostream>
#include<algorithm>
using namespace std;
int a[1010],b[1010];
int main(){
int t,tt,n,x;
int s,ans;
while(scanf("%d%d",&n,&x)!=EOF)
{
   for(tt=0;tt<n;tt++)
   {
    scanf("%d",&a[tt]);

   }
   for(tt=0;tt<n;tt++)
   {
    scanf("%d",&b[tt]);

   }
   sort(a,a+n);
   sort(b,b+n);
   ans=0;
   for(tt=0;tt<n;tt++)
   {
    s=a[tt]+b[n-tt-1]-x;
    if(s>0)
     ans+=s;
   }
   printf("%d\n",ans);
}
    return 0;
}


E题:状态传递,再加上点floyd算法求解,(floyd在求最短路上的优势在于,

可以一次性求解多个最短路,不好的是耗时),先初始化d[i][j]=0; 若a比b

强,则d[a][b]=1; d[b][a]=2(表示b比a弱);代码:

import java.io.*;
import java.util.*;
import java.math.*;

public class f {
public static void main(String args[]) {
   BigInteger[] h=new BigInteger[65];
   h[0]=BigInteger.ONE;
   h[1]=BigInteger.ONE;
   for(int i=2;i<61;i++)
    h[i]=BigInteger.ZERO;
   for(int i=2;i<=60;i++)
    for(int j=0;j<i;j++)
     h[i]=h[i].add
      (h[j].multiply(h[i-j-1]));
  
  
   int a,b,c,d;
   BigInteger x;
   Scanner cin = new Scanner(new BufferedInputStream

(System.in));
   while(cin.hasNext()) {
    a=cin.nextInt();
   
    if(a==0) {
     break;
    }
   
    System.out.println (h[a/2]);
   }
}

}

F题:地大恐龙博物馆买票问题:裸的Catalan数
我的算法不怎么样,递归式:
  h(n)=((4*n-2)/(n+1))*h(n-1);比较好
代码:
import java.io.*;
import java.util.*;
import java.math.*;

public class f {
public static void main(String args[]) {
   BigInteger[] h=new BigInteger[65];
   h[0]=BigInteger.ONE;
   h[1]=BigInteger.ONE;
   for(int i=2;i<61;i++)
    h[i]=BigInteger.ZERO;
   for(int i=2;i<=60;i++)
    for(int j=0;j<i;j++)
     h[i]=h[i].add
      (h[j].multiply(h[i-j-1]));
  
  
   int a,b,c,d;
   BigInteger x;
   Scanner cin = new Scanner(new BufferedInputStream

(System.in));
   while(cin.hasNext()) {
    a=cin.nextInt();
   
    if(a==0) {
     break;
    }
   
    System.out.println (h[a/2]);
   }
}

}
G题:包子的密码;求亲和数,又是数论题,题目四秒,我的暴力30秒左右,没

心思优化,直接打表:
另外这题输出让我费了不少功夫,sprintf用的不熟,呵呵,不过早知道打表

就无所谓了
代码:
#include<cstdio>
//#include<cmath>
#include<iostream>
#include<string>
using namespace std;
int a[27][2]={ {220,284},{1184,1210},{2620,2924},{5020,5564},

{6232,6368},{10744,10856},{12285,14595},{17296,18416},

{63020,76084},{66928,66992},{67095,71145},{69615,87633},

{79750,88730},{100485,124155},{122265,139815},{122368,123152},

{141664,153176},{142310,168730},{171856,176336},{176272,180848},

{185368,203432},{196724,202444}};
int main()
{

int a1,a2,b,i,j,cas=0;
char ii[20];
string iii,str;
scanf("%d%d",&a1,&a2);
if(a1>a2)
{
   b=a1;
   a1=a2;
   a2=b;
}
for(i=0; i<=22; i++)
{
  
   if(a[i][0]>a1 && a[i][1]<a2)
   {
    cas++;
    sprintf(ii,"%d %d\n",a[i][0],a[i][1]);
    iii=ii;
    str+=iii;
   }
}
printf("%d\n",cas);
cout<<str;
//system("pause");
return 0;
}

后面的题目都没看(没时间,估计也做不出来)
下文转自http://user.qzone.qq.com/277930484/
H题: 锄大地(其实跟打牌毫无关系)无非是找数字规律,推公式了,这是题

目的数据:1张牌:不计分 2-7张牌:n分 8-9张牌:2n+7分 10-12张牌:3n

+2*9+7 13-16张牌:4n+3*12+2*9+7 17-21张牌:5n+4*16+3*12+2*9+7 可以发

现区间段的数字个数为 2,3,4,5,6....(从数字8开始);可以发现得分的常数

项为7,2*9+7,3*12+2*9+7,....(从数字8开始):每一个常数项和上一个数段

的最后一个得分结果相同!!!;可以发现系数为:2,3,4,5,6.....;接下来

,就是你的代码实现问题了代码:#include<stdio.h>
int Case;
__int64 d[1501];
void p()
{
    int i,j,s,k,t;
    d[0]=d[1]=0;
    t=2; s=7; k=7;
    for(i=2;i<=7;i++)
        d[i]=i;
    for(i=8;i<=1500;i++)
    {
        d[i]=i*t+s;
        if(i==k+t)
        {
            k+=t;
            s=d[i];
            t++;
        }
    }
}
int main()
{
    int j,a,b,c,A=0,B=0,C=0;
    p();
    scanf("%d",&Case);
    for(int i=1;i<=Case;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        printf("Case %d:\n",i);
        printf("Leefour:%I64d\n",d[a]);
        printf("Eli_love:%I64d\n",d[b]);
        printf("Pmonkey:%I64d\n",d[c]);
        A+=d[a]; B+=d[b]; C+=d[c];
    }
    __int64 min=-1;
    j=0;
    if(A>min){min=A; j=1;}
    if(B>min){min=B; j=2;}
    if(C>min){min=C; j=3;}
    if(j==1) printf("Leefour ");
    else if(j==2) printf("Eli_love ");
    else if(j==3) printf("Pmonkey ");
    printf("lose!\n");
    return 0;
}


总结:
java不是很熟练,所以写水题的速度不行
java的类库用了解的太少
java细节小错误导致浪费时间调试的事情屡有发生

?CUGB第四届程序设计大赛解题报告 - 橙衣少年 - 跟着我勇敢地走下去

java效率实在不行,正式比赛还是cpp比较靠谱,如图