2017.2.6测试总结

2017.2.6测试总结
第一题:

The Rock Game [Tom Conerly, 2010]

 

有N (1 <= N <= 15)位二进制数,一开始是N个0, 你每次对当前状态进行一次操作,把当前状态的某个位置取反(即原来是0的变成1,原来是1的变成0)。 但是产生的新状态必须是之前从来没产生的。你的任务是:从N个0的状态出发,把2^N个状态都访问一次,最后重新能回到N个0的状态。 请你把这个转换过程输出来,如果有多种方案成立,任意输出一种。

 

例如:      

步骤   三位二进制

-----------------

0      O  O O  开始状态

1      O  O X  把最后一个变成1,即001

2      X  O X  变成101

3      X  O O  变成100

4      X  X O  变成110

5      O  X O  变成010

6      O  X X  变成011

7      X  X X  变成111

发现此时111只能改变一个位置的话,无法变回000状态了,因此这是不可行的方案。

下面是可行的一种方案。

 

步骤   三位二进制

-----------------

0      O  O O 

1      O  X O 

2      O  X X 

3      O  O X 

4      X  O X 

5      X  X X 

6      X  X O 

7      X  O O 

8      O  O O 

 

这就符合条件了,每种状态都访问一次,且最后回到状态0。

 

 

输入格式: rocks.in

 

* 一行:一个整数: N

 

输出格式: rocks.out

 

* 第1..2^N+1行: 每行是一种由N个字符组成的状态:'O' 或 'X'。

 

 其中字符‘X’表示1。

样例输入:

 

3

 

样例输出:

 

OOO

OXO

OXX

OOX

XOX

XXX

XXO

XOO

OOO

【题目分析】

这一题题意是每次随机将N位的二进制数的一位反转,而且每次反转得到的数都不一样,先从N个0开始反转,然后反转出2^N个状态,最后反转出N个0的状态。

看到这个是N位的二进制数,很容易就想到位运算,0与1异或是等于1,1与1异或是等于0,这恰好就是反转的位运算,至于要反转哪一位,将1左移0到n-1位枚举出的答案进行标记就行了。

【程序清单】

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,sum,i,j,k,tt,a[50000],f[50000],b[20];
char ch;
int getnum()
{
	ch=getchar();
	for (;ch<'0' || ch>'9';ch=getchar());
	int ret=0;
	for (;ch>='0' && ch<='9';ch=getchar()) ret=ret*10+ch-48;
	return ret;
}
void dfs(int t,int num)
{
	for (int i=0;i<n;i++)
	{
		int x=(1<<i)^t;
		if (x==0 && num+1==sum)
		{
			tt=1;
			a[num]=0;
			return;
		}
		if (!f[x])
		{
			f[x]=1;
			dfs(x,num+1);
			if (tt)
			{
				a[num]=x;
				return;
			}
			f[x]=0;
		}
	}
}
void init()
{
	n=getnum();
}
void solve()
{
	for (i=1;i<=n;i++) printf("O");
	printf("\n");
	f[0]=1;sum=2;
 	for (i=2;i<=n;i++) sum*=2;
	dfs(0,0);
	for (i=0;i<sum;i++)
	{
		j=0;
		memset(b,0,sizeof(b));
		while (a[i]!=0)
		{
			j++;
			b[j]=a[i]%2;
			a[i]/=2;
		}
		for (k=n;k>=1;k--)
		if (b[k]==1) printf("X");else printf("O");
		printf("\n");
	}
}
int main()
{
	freopen("rocks.in","r",stdin);
	freopen("rocks.out","w",stdout);
	init();
	solve();
	return 0;
}


第二题:

Test Taking [Tom Conerly, 2010]

 

有N (1 <= N <= 1,000,000)个true 或者false的问题。

其中答案是true的问题的个数有K种可能:t_1, t_2, t_3,..., t_K (0 <= t_i<= N; 0 <= K<= 10,000). 但是我们无法知道具体哪个问题的答案是true或false。

 

现在Bessie要回答这N个问题,为了在运气最差的情况下答对的题目最多,她必须采取最优策略。比如有6个问题, N=6, k = 2,t_1 = 0, t_2 = 3. 也就是说,这6个问题中,真命题的个数可能是0个,也可能是3个。那么Bessie为了在运气最差的情况答对的问题最多,她可以回答每个问题都是的答案都是false. 可以看出,如果她运气好的话,她能答对6题,但如果运气差的话(即有3到是true的问题),那么她只能答对3题(因为她的回答是6个false)。

因此,Bessie在最差的情况下能答对3题。

    我们来看看,如果其它策略,Bessie能否在运气最差的情况下答对的题目超过3题。比如:Bessie的回答是3个true, 3个false. 那么最坏的情况是什么呢?由于Bessie并不知道具体的某问题的答案,可能她全部答错。也就是3个真命题,她的回答是false,而3个假命题,她却刚好回答是yes,这种情况Bessie答对0道题,显然没有上面的策略优。

 

   你的任务是:在采取最优策略下,她在运气最差时,最多能答对几道题?

 

输入格式:

 

* 第1行:两个整数: N and K

 

*第 2..K+1行: 第i+1只有一个整数: t_i

 

SAMPLE INPUT ( teststr.in):

 

6 2

0

3

 

输出格式:

 

* 第1行:一个整数,在采取最优策略下,她在运气最差时,最多能答对几道题?

 

SAMPLE OUTPUT (teststr.out):

 

3

【题目分析】

这一题题意是在最优策略和最差运气下,输出k个可能对的题最多会对的题。

直接暴力做的话肯定超时,时间复杂度(NK)。

进一步分析的话,假设1000个问题,只有两个可能:420个true或者680个true

如果策略是500个false,最差运气下

第一种可能:对的题是(500-420)=80个

第二种可能:对的题是(680-500)=180个

因为题目要求运气最差,所以取最小值只有80个

可以看得出两种可能得出对的题只是看最小值,所以为了让最小值最大化,就只可能是420和680取中间值550,我们试着往下模拟一下:

第一种可能:对的题是(550-420)=130个

第二种可能:对的题是(680-550)=130个

所以对的题是130个,显然比上面的500要多。

那么如果k>2,就取相邻两个可能,当然不要忘记全部选对和全部选错的情况。

为什么是相邻两个可能呢?

如果再多一个可能是500个true的话,上面所述的550对于500来说只是50个对的

显然(500+680)/2=590有90个对的,显然比50个多,这就证明了肯定是用相邻两个来做。

【程序清单】

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
int n,m,i,ans,a[1000005];
char ch;
bool cmp(int a,int b)
{
	return a<b;
}
int getnum()
{
	ch=getchar();
	for (;ch<'0' || ch>'9';ch=getchar());
	int ret=0;
	for (;ch>='0' && ch<='9';ch=getchar()) ret=ret*10+ch-48;
	return ret;
}
void init()
{
	n=getnum();m=getnum();
	for (i=1;i<=m;i++) a[i]=getnum();
}
void solve()
{
	sort(a+1,a+m+1,cmp);
	ans=a[1];
	if (n-a[m]>ans) ans=n-a[m];
	for (i=1;i<m;i++) if ((abs(a[i]-a[i+1])/2)>ans) ans=abs(a[i]-a[i+1])/2;
	printf("%d",ans);
}
int main()
{
	freopen("teststr.in","r",stdin);
	freopen("teststr.out","w",stdout);
	init();
	solve();
	return 0;
}

第三题:

Need For Speed [Jeffrey Wang, 2007]

 

Bessie 想参加赛车比赛,他的赛车质量是M (1 <= M <= 1,000) ,马力是F (1 <= F<= 1,000,000). 为了提升赛车性能,他可以到加工店添加一些零件。加工店有N(1 <= N <=10,000)种零件,编号1..N, 每种零件只有一件。

 

零件P_i 能增加的马力是F_i (1 <= F_i<= 1,000,000) ,它的质量是

M_i (1 <= M_i <= 1,000). 根据牛顿第二定理F =MA,( F 是力, M是质量, A 是加速度).Bessie想让他的车的加速度最大 (如果有多种方案,让赛车的质量最小),他应该配置哪些零件呢?

 

例如:开始赛车的F=1500 , M=100.有4种零件:

 

          i  F_i M_i

          1  250  25

          2  150   9

          3  120   5

          4  200   8

 

假如只配置零件2, 那么加速度将会是:(1500+150)/(100+9)= 1650/109 = 15.13761.

 

下面的表格用4位二进制数表示配置或不配置零件,得到各种各样的加速度:

       

状态        F           M       F/M

0000      1500         100   15.0000

0001      1700         108   15.7407

0010      1620         105   15.4286

0011      1820         113   16.1062

0100      1650         109   15.1376

0101      1850         117   15.8120

0110      1770         114   15.5263

0111      1970         122   16.1475 <-- highest F/M

1000      1750         125   14.0000

1001      1950         133   14.6617

1010      1870         130   14.3846

1011      2070         138   15.0000

1100      1900         134   14.1791

1101      2100         142   14.7887

1110      2020         139   14.5324

1111      2220         147   15.1020

 

因此,应该配置零件2, 3, 4.

 

PROBLEM NAME: sboost

 

输入格式:

 

* 第 1行:三个整数: F, M, N

 

* 第 2..N+1行:第i行有两个整数: F_i 、 M_i

 

SAMPLE INPUT (file sboost.in):

 

1500 100 4

250 25

150 9

120 5

200 8

 

输出:

 

* 第1..P行: P 是你要配置的零件的个数。如果不需要配置,则输出NONE. 否则从小到大输出你配置的零件的下标。答案是唯一的。

 

SAMPLE OUTPUT (file sboost.out):

 

2

3

4

【题目分析】
这一题题意是为赛车尽可能增加零件来获取最大加速度,如果两个零件加速度一样的话就取质量较小的。
这一题可以用贪心去做。把各个零件按照加速度从大到小排序,然后再选择合适的零件来配置。
如果(F/M)<(Fi/Mi)<(Fj/Mj),那么就可以得出((F+Fi)/(M+Mi))<((F+Fj)/(M+Mj))
但是千万不要漏了零件加速度必须大于赛车当前的加速度的前提条件。
【程序清单】
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
struct node
{
	double f,m;
	int num;
};
int n,i,b[10005];
double f,m;
node a[10005];
char ch;
int getnum()
{
	ch=getchar();
	for (;ch<'0' || ch>'9';ch=getchar());
	int ret=0;
	for (;ch>='0' && ch<='9';ch=getchar()) ret=ret*10+ch-48;
	return ret;
}
bool cmp(node a,node b)
{
	if ((a.f/a.m)!=(b.f/b.m)) return (a.f/a.m)>(b.f/b.m);
	return a.m<b.m;
}
bool cmq(int a,int b)
{
	return a<b;
}
void init()
{
	f=getnum();m=getnum();n=getnum();
	for (i=1;i<=n;i++)
	{
		a[i].f=getnum();a[i].m=getnum();a[i].num=i;
	}
}
void solve()
{
	sort(a+1,a+n+1,cmp);
	for (i=1;i<=n;i++)
	{
		if ((a[i].f/a[i].m)<(f/m)) break;
		if ((a[i].f/a[i].m)==(f/m) && a[i].m>m) break;
		f+=a[i].f;m+=a[i].m;
		b[++b[0]]=a[i].num;
	}
	if (b[0]==0)
	{
		printf("NONE");
		return;
	}
	sort(b+1,b+b[0]+1,cmq);
	for (i=1;i<=b[0];i++) printf("%d\n",b[i]);
}
int main()
{
	freopen("sboost.in","r",stdin);
	freopen("sboost.out","w",stdout);
	init();
	solve();
	return 0;
}


猜你喜欢

转载自blog.csdn.net/qq_36679229/article/details/54925703