rejudge很有趣
下午队内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
题目:求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公式),测试数据没过,遂放弃?
poj3984
顶嵌杯决赛第二题,简单的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第四届程序设计大赛解题报告
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细节小错误导致浪费时间调试的事情屡有发生
?
java效率实在不行,正式比赛还是cpp比较靠谱,如图