C. Monty Hall problem


Time Limit: 1000ms



Memory Limit: 65536KB

64-bit integer IO format:

%lld      Java class name: Main

​Submit​​​ ​​​Status​​​ ​​​ PID: 44578​


蒙提霍尔问题,亦称为蒙特霍问题或三门问题(Monty Hall problem),是一个源自博弈论的数学游戏问题.



这个游戏的玩法是:参赛者会看见三扇关闭了的门,其中一扇的后面有一辆汽车,选中后面有车的那扇门就可以赢得该汽车,而另外两扇门后面则各藏有一只山羊。当参赛者选定了一扇门,但未去开启它的时候,知道门后情形的节目主持人会开启剩下两扇门的其中一扇,露出其中一只山羊。主持人其后会问参赛者要不要换另一扇仍然关上的门。问题是:换另一扇门会否增加参赛者赢得汽车的机会率?



——wikipedia



 



现在我们来研究n扇门的蒙提霍尔问题:一共有n扇关闭了的门。只有一扇门后是汽车,其他n-1扇门后是山羊。参赛者选定一扇门后,知道门后情形的节目主持人会开启剩下n-1扇门的其中n-2扇,露出n-2只山羊。主持人其后会问参赛者要不要换另一扇仍然关上的门。求参赛者换门之后获得汽车的概率。



 


Input


第一行为一个整数T,代表数据组数,T<=1000。



接下来T行,每行一个正整数n,3<=n<=10^18。n的含义如题意所示。



 


Output


答案要求输出最简分数形式:p/q (p,q互素) 。表示参赛者换门之后获得汽车的概率。


【解题思路】:


问题的答案是可以:当参赛者转向另一扇门而不是维持原先的选择时,赢得汽车的机会将会加倍。


有三种可能的情况,全部都有相等的可能性(1/3)︰


参赛者挑山羊一号,主持人挑山羊二号。转换将赢得汽车。


参赛者挑山羊二号,主持人挑山羊一号。转换将赢得汽车。



#个人赛第三场解题总结#_#include

故赢得汽车概率1-1/3=2/3

推而广之:n扇门,对应答案n-1/n;(推理不算很完整,此题有待进一步思考)

代码:

#include <iostream>
using namespace std;
int main()
{
int n;
long long m,i,j;
cin>>n;
while(n--)
{
cin>>m;
cout<<m-1<<"/"<<m<<endl;
}
}


D. Gandalf vs Witch-king of Angmar


Time Limit: 1000ms


Memory Limit: 65536KB

64-bit integer IO format: %lld      Java class name:

Main

​Submit​​​ ​​Status​​​ ​​ PID: 44579​


在Minas Tirith保卫战中,Gandalf与Witch-king of Angmar相遇了,他们打得惊天动地,震惊了乡土胖子LYE,于是乎,他想知道他们决斗的威力乡土胖子LYE已经得知Gandalf所有的招数列表以及Angmar所有的招数列表,每个招数名以字符表示,每个招数的威力就是这个字符的ASCII码值(32 ≤ASCII ≤126)。决斗时,Gandalf放出一招,Angmar放出一招,两个招数相遇时放出的威力即为两招的威力之和的立方,所有招数对完以后释放的总威力为每次对决释放的威力的相加的结果。现在,乡土胖子LYE想请你帮助他计算一下Gandalf与Angmar对决的总威力。




Input


第1行是一个整数T,代表测试数据的组数。


∙ 第2行开始的2T行,每两行是一组测试数据。


∙ 每组测试数据的每一行均为一个字符串(32 ≤ ASCII码≤ 126的任


意ASCII字符),而且两个字符串的长度(0 ≤lengtℎ ≤ 1000)相同


Output


对应于每组输入,首先输出数据编号(如样例所示)


∙ 然后输出一个数,代表求得的结果(注意:结果要 mod 1000000007)


Sample Input


2abcdef ccc ddd


Sample Output


Case #1: 23646573Case #2: 23641797


Hint


第一组样例即为((97+100)^3+(98+101)^3+(99+102)^3)%1000000007=236465732



【解题思路】:

 字符串处理:

代码:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <string.h>
#include <algorithm>
using namespace std;
const double eps=1e-6;
const int pi=acos(-1.0);
int aa[1002];
char s1[1001],s2[1001];
int main()
{
int t,j=1;
scanf("%d",&t);
getchar();
while(t--)
{
long long h3=0;
gets(s1);
gets(s2);
int a1=strlen(s1);
for(int i=0; i<a1; i++)
{
h3+=(s1[i]+s2[i])*(s1[i]+s2[i])*(s1[i]+s2[i]);
h3%=1000000007;
}
printf("Case #%d: ",j++);
printf("%lld\n",h3);
}
return 0;
}


E. Araleii & Bill的冠名权争夺战 again


Time Limit: 1000ms


Memory Limit: 65536KB

64-bit integer IO format: %lld      Java class name: Main

​Submit​​​ ​​Status​​​ ​​ PID: 44580​


众所周知,WL大神有个用来卖萌的昵称叫做Araleii,此外,他还有个英文名叫做Bill。然而,随着WL大神被越来越多的人膜拜景仰,他的两个名字都想获得WL大神的冠名权,并由此展开了一场旷日持久的争夺战。

距离上一次决斗已经过去了一年,在这一年中WL大神变得越来越神,于是上一场决斗的战败者(就不告诉你是谁)想开始新的一次决斗,夺回WL大神的冠名权。

这次,他们不想再取石子了,而是直接用石子来战斗。Araleii和Bill找来n个石子,石子的战斗力分别为1、2、3、……、n(即第i个石子的战斗力为i)。理论上说,战斗力高的石子将会战胜战斗力低的石子,但是这其中有m个例外(即存在m对石子A、B,A的战斗力大于B,但是B会战胜A)。他们规定规则如下:

首先,Araleii选取一个石子,若Bill不能从剩下的石子中选出一个可以战胜该石子的石子,则Araleii获胜,否则Bill选出一个可以战胜该石子的石子。

然后(如果之前Araleii没有获胜),Araleii再从除之前两个石子外剩下的石子中选取一个石子,若可以战胜Bill的石子,则Araleii获胜,否则Bill获胜。

现在,Araleii想知道自己是否可以获胜(由于Araleii和Bill都是WL大神的名字,继承了WL大神的无上智慧,所以他们每次取石子时都会采取最优策略)。


Input


输入数据有多组。

第一行输入一个整数T,表示数据组数。

之后T组每组第一行两个整数N、M,表示石子个数和例外个数(1≤ N≤10^5,0≤M≤min(10^6,N*(N-1)/2))。

之后M行每行两个整数x、y,表示第x个石子反而可以战胜第y个石子(1≤x<y≤N)


Output


每组样例输出一行,如果Araleii获胜,输出“Bill will lose HAHA”,否则输出“I this idiot”(输出不包括引号)。


Sample Input


21 03 1 1 3


Sample Output


Bill will lose HAHABill will lose HAHA


Hint

对于第一组样例,Araleii把第1个石子取出来后Bill就没得取了,所以Araleii获胜。

对于第二组样例,第1个石子可以战胜第3个石子,第3个石子可以战胜第2个石子,第2个石子可以战胜第1个石子,所以无论两人怎么拿,最终都是Araleii获胜。

【解题思路】:

第一个做出此题之后,突然明白了比赛的时候什么情况都有可能发生,整场比赛看的就是谁胆子大,实在想不出来,在所有情况下,都输出样例,也不是不可能的事,此题确实如此,之后想了想,确实如此:当A取正好必胜时,A胜;当A无必胜可能时,则B必胜,则A可以直接取出去B的那个点到必胜点。因此最后都是A必胜



G. MLX的疯狂睡眠


Time Limit: 1000ms


Memory Limit: 65536KB

64-bit integer IO format: %lld      Java class name: Main

​Submit​​​ ​​Status​​​ ​​ PID: 44582​


在一个寝室中,有早上6点多起床跑自习室或者图书馆,晚上11点多回寝室洗洗直接睡觉的神牛(真是神一般的存在);也有早上11点多起来直接吃饭,下午玩一会累了又sleep的睡神;也有白天一直陪妹子,大晚上和寝室程序猴子作伴的泡神;也有早上不知道何时起,从下午到第二天早些时候(确实早啊!)一直code的神码手····那么现在问题来了,寝室本来是一个非常友好的team,但是为了证明自己的睡眠行为是大学最完美的,他们决定来一场惊天地的辩论····MLX作为寝室的一员,突然做出一个疯狂的决定:统计出寝室每一个成员的睡眠时间段(每一个成员可能有多个睡眠时间段),然后将亲自实践每一个成员睡眠方式,然后再决定谁的更好。聪明的您可能会想这样一个问题:如果MLX从进入一个睡眠段开始到结束中途不醒,MLX那一天最多能睡多少次?

现在将问题进一步抽象为:一天内有n个睡眠区间,每一个睡眠区间分别为距离当天0点的第Si秒开始,第Ti秒结束。对于每一次睡眠,MLX都可以参与或者不参与,如果选择了,那么MLX就必须将本次睡眠进行到底。此外,参与睡眠的时间不能重复(即使是刚开始的瞬间和结束的瞬间的重复也是不允许的),请问MLX最多能参与多少次睡眠?


Input


第一行输入T,表示T组测试数据。

每一组的第一行输入n,表示有n个睡眠区间(1<= n <=10^5 )

接下来n行,每一行输入两个整数Si,Ti(空格隔开),表示睡眠区间的开始和结束时间(1<= Si< Ti< 24*3600)


Output


MLX最多参与的睡眠次数


Sample Input


151 3 2 5 4 7 6 9 8 10


Sample Output


3


Hint

参与的睡眠编号依次是(1,3,5)

【解题思路】:

跟nyoj上会场安排一个思路:依次统计每一个事件开始时间是否大于上一次事件的结束时间,满足累加即可。

代码:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <string.h>
#include <algorithm>
using namespace std;
const double eps=1e-6;
const int pi=acos(-1.0);
char s1[1001],s2[1001];
struct node
{
int x,y;
} aa[100010];
node p;
bool cmp(node a1,node b1)
{
if(a1.y!=b1.y)
return a1.y<b1.y;
return a1.x<b1.x;
}
int main()
{
int t,n,m,i,j;
cin>>t;
while(t--)
{
int sum=1;
cin>>n;
for(i=0; i<n; i++)
cin>>aa[i].x>>aa[i].y;
sort(aa,aa+n,cmp);
int h1=aa[0].y;
for(i=1; i<n; i++)
{
if(aa[i].x>h1)
{
sum++;
h1=aa[i].y;
}
}
cout<<sum<<endl;
}
return 0;
}

H. Star Trek: First Contact


Time Limit: 1000ms


Memory Limit: 65536KB

64-bit integer IO format: %lld      Java class name: Main

​Submit​​​ ​​Status​​​ ​​ PID: 44583​


星舰进取号(NCC-1701-E)正在宇宙间做例行巡航时,舰长Jean-Luc Picard接到密电,称一艘Borg方块正以曲速9.99(2.3 × 10^9km/s)驶向位于001星区的地球,并沿途摧毁大量殖民星球。由于担心Picard舰长过去被Borg人同化的经历为作战增加“不稳定因素”,星际舰队指挥部命令元首级星舰进取号前去监控及巡逻Romulans中立区,以防Romulans人趁机进犯。然而,在获知舰队遭到大量损失时,Picard舰长决定抗命加入战役。在抵达001星区时,Picard舰长发现Borg方块非常强大,而目前进取号仅有N枚光子鱼雷(Photon Torpedo),第i枚光子鱼雷发射会消耗进取号ai的能量,能够对Borg方块的结构完整性造成bi的损伤(结构完整性≤0时,Borg方块毁灭)。已知进取号星舰的总能量为A, Borg方块的结构完整性为B,作为进取号星舰的大副(NO.1 or First Officer),

Picard舰长要求你计算进取号是否能够摧毁Borg方块。


Input


∙ 第1行是一个整数T(T ≤ 5),代表测试数据的组数。

∙ 第2行开始的3T行,每三行是一组测试数据。

∙ 每组测试数据的第一行为三个整数A(0 ≤ A ≤ 1000),B(0 ≤ B ≤ 1000),N(0 ≤ N ≤ 100),分别表示进取号星舰的总能量、Borg方块的结构完整性、光子鱼雷的数量;第二行为N个整数,每个数表示发射第i枚光子鱼雷消耗的能量ai(0 ≤ ai ≤ 1000);第三行为N个整数,每个数表示发射第i枚光子鱼雷能够对Borg方块的结构完整性造成bi(0 ≤ bi ≤ 1000)的损伤。


Output


对应于每组输入,首先输出数据编号(如样例所示)。

 如果进取号能够摧毁Borg方块则输出”YES”,否则输出”NO”(PS: 输出内容无引号””)。


Sample Input


16 20 41 2 3 2 4 6 12 7


Sample Output


Case #1: YES

转化成一维0-1背包问题求解:用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其​​状态转移方程​​便是:f[i][v]=max{ f[i-1][v], f[i-1][v-w[i]]+v[i] }。可以压缩空间,f[v]=max{f[v],f[v-w[i]]+v[i]}


代码:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <string.h>
#include <algorithm>
using namespace std;
#define Max(a,b) a>b?a:b
const double eps=1e-6;
const int pi=acos(-1.0);
char s1[1001],s2[1001];
int hh[20002];
struct node
{
int hao,hai;
} aa[10001];
node p[10000];
bool cmp(node a1,node b1)
{
return a1.hai>b1.hai;
}
int main()
{
int t,m,i,j=1;
scanf("%d",&t);
while(t--)
{
printf("Case #%d: ",j++);
int A,B,N;
scanf("%d %d %d",&A,&B,&N);
memset(hh,0,sizeof(hh));
for(i=0; i<N; i++)
{
scanf("%d",&aa[i].hao);
}
for(i=0; i<N; i++)
{
scanf("%d",&aa[i].hai);
}
//sort(aa,aa+N,cmp);
for(int i=0; i<N; i++)
for(int k=A;k>=aa[i].hao;k--)
{
hh[k]=Max(hh[k],hh[k-aa[i].hao]+aa[i].hai);
}
// hh[k]=max(hh[k],hh[k-aa[i].hao]+aa[i].hao);
int ans=0;
for(i=0; i<=A; i++)
{
ans=Max(hh[i],ans);
}
printf("%s",ans>=B?"YES\n":"NO\n");
// if(ans>=B)
// puts("YES");
// else puts("NO");
}
return 0;
}


I. 平面切割者


Time Limit: 1000ms


Memory Limit: 65536KB

64-bit integer IO format: %lld      Java class name: Main

​Submit​​​ ​​Status​​​ ​​ PID: 44584​


你是一个平面切割者,有一个看上去很酷的工作——切割平面。现在你面前有一个平面,平面上有一大一小两个同心圆。你的工作是:画n条大圆的弦(这些弦在大圆内两两相交)来切割平面。各弦均与小圆相交于两点,且不存在三弦共点,也不存在两弦和小圆交于一点的情况。请问你切割完平面后,大圆内的平面被切割成了多少个区域? 


Input


第一行输入一个整数T(T<=20000),表示输入数据的组数。

接下来T行输入一个整数n(0<=n<20000),表示画的大圆的弦的条数。


Output


输出T行,每行输出一个数,表示大圆内划分成的区域数。


Sample Input


212


Sample Output


48


Hint

连接圆上任意两点的线段称为弦。

【解题思路】画图,将1,2,3,4根弦的情况画出来,找规律即可。递推式 f(i) = f(i-1) + i + 2,数组打表,

 记得有一个直线与平面相交定理,每增加一条直线,就会增加i-1个点具体怎么推导的记得不是很清楚了。

代码:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <string.h>
#include <algorithm>
using namespace std;
//const int maxn=~OU>>2;
const double eps=1e-6;
const int pi=acos(-1.0);
char s1[1001],s2[1001];
int A[20002];
int main()
{
A[0]=2;
A[1]=4;
for(int i=2;i<=20000;i++)
A[i]=A[i-1]+i+2;
int t,n,m,i,j;
scanf("%d",&t);
while(t--)
{
scanf("%d",&m);
printf("%d\n",A[m]);
}
return 0;
}


J. 顽皮的字母


Time Limit: 1000ms


Memory Limit: 65536KB

64-bit integer IO format: %lld      Java class name: Main

​Submit​​​ ​​Status​​​ ​​ PID: 44586​


大家都知道有26个英文字母,abcdef…。由这些字母组成了一个字符串,但是,由于这些字母日久生情,有一些字母挨在一起的时候就会一起跑走玩耍。我们对26个字母编号1~26,就是说1对应a,…,26对应z,第i个字母和第i+1个字母相互有好感,挨在一起会跑开,i为1~26里面的奇数,跑开之后空位由后面的字母补上。现在问题来了,输入一个长度为n(n<10^5)的字符串,这个字符串包含挨在一起的情况比如ab挨在一起,问最后剩下的字符串是什么。


Input


第1行为数据组数T(T<=100)。

第2行到第T+1行为输入字符串,每行一个字符串。

保证输入全为英文小写字母


Output


对于每个字符串,输出一行最后剩下的字符串。如果最后所有的字母都跑开了输出“sad!”,不包括引号。


Sample Input


2ababababcabacda


Sample Output


caa


【解题思路】:

开始用的是数组模拟:

#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <math.h>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <cstring>
#include <sstream>
#include <queue>
#include <stack>
using namespace std;
char s1[100001],s2[100001];
int main()
{
int i,j,k,l,t,ans;
cin>>t;
getchar();
while(t--)
{
cin>>s1;
l=strlen(s1);
ans=1;
s2[0]=s1[0];
for(i=1; i<l; i++)
{
if(s1[i]%2!=0)//当前字母为 a,c,e,g……
{
if (s1[i]+1==s2[ans-1]) ans--;
//
//满足ab,cd……把ans的已存的字母删除
else s2[ans++]=s1[i];
//添加当前字母
}
else
//当前字母为b,d,f,h……
{
if (s1[i]-1==s2[ans-1]) ans--;
else s2[ans++]=s1[i];
}
}
s2[ans]='\0';
if (!ans) puts("sad!");//所有的字母已经消除
else printf("%s\n",s2);
}
return 0;
}

用stack实现:


//开一个栈,让所给字母序列的第一个字母入栈,然后判断第二个字母是否与栈顶字母有好感,
//有的话,弹出栈顶字母,进行第三个字母的操作,否则将第二个字母也压入栈,
//一直重复这个操作直到检查完所有字母。最后判断栈是否为空,若为空则说明所有字母都跑完了,
//否则将栈中字母全部弹出
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <math.h>
#include <map>
#include <set>
#include <vector>
#include <string.h>
#include <sstream>
#include <queue>
#include <stack>
using namespace std;
char s1[1001],s2[1001];
stack<int>a1;
int main()
{
int t,i,j;
cin>>t;
getchar();
while(t--)
{
cin>>s;
int len=strlen(s);
for(i=0; i<len; i++)
{
int ans=s[i]-'a'+1;
if(!a1.empty()&&(ans%2==0&&a1.top()==s[i]-1||ans%2==1&&a1.top()==s[i]+1))//
{
a1.pop();
}
else
{
a1.push(s[i]);
}
}
stack<int>a2;
while(!a1.empty())
{
a2.push(a1.top());
a1.pop();
}
if(a2.empty())
{
printf("sad!\n");
}
else
{
while(!a2.empty())
{
printf("%c",a2.top());
a2.pop();
}
cout<<endl;
}
}
}