您的位置:首页 > 大数据 > 人工智能

2016 Multi-University Training Contest 7

2016-08-10 17:22 204 查看

1. 1002-HDU 5810 Balls and Boxes

题意:给定n个球,m个盒子,将n个球抛入m个盒子,对于每种情况,定义



 是第i个盒子中球的个数,

 是所有盒子中的球的个数的平均数,即n/m。求V的期望E(V)。

题解:

首先化简公式。



又由于



所以



首先对于每个盒子,每个球落入其中的概率是p=1/m,落不进的概率为1-p=1-1/m。所以对于每个盒子,

 满足二项分布。



所以



代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;

int main()
{
int n,m;
while(scanf("%d%d",&n,&m))
{
if(n==0&&m==0) break;
LL fenzi=1ll*n*(m-1),fenmu=1ll*m*m;
LL g=__gcd(fenzi,fenmu);
printf("%I64d/%I64d\n",fenzi/g,fenmu/g);
}
return 0;
}


2. 1005-HDU 5813 Elegant Construction

题意:让你构造出一个图使得其满足第i个点能到达的点的个数为ai个,没有环和重边。

题解:按 ai 从小到大排序,在比 i 点与比其 ai 值小的点 j 之间连 aj 条边即可,只要出现 ai 值大于i,则一定不可能满足。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX=1000+10;
struct node
{
int id,x;
bool operator <(const node &a)
{
return x<a.x;
}
}a[MAX];

int main()
{
int T;
scanf("%d",&T);
for(int tcase=1;tcase<=T;tcase++)
{
int n;
scanf("%d",&n);
int sum=0;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i].x);
sum+=a[i].x;
a[i].id=i+1;
}
sort(a,a+n);
int flag=1;
for(int i=0;i<n;i++)
{
if(a[i].x>i)
{
flag=0;
break;
}
}
printf("Case #%d: %s\n",tcase,flag?"Yes":"No");
if(flag)
{
printf("%d\n",sum);
for(int i=0;i<n;i++)
{
for(int j=0;j<a[i].x;j++)
{
printf("%d %d\n",a[i].id,a[j].id);
}
}
}
}
return 0;
}

3. 1009-HDU 5818 Joint Stacks

题意:模拟栈操作,并在栈操作基础上多加一种操作merge A B,该操作可将栈A和栈B内的元素按输入顺序塞进栈A中,并清空栈B。问在执行pop操作时,弹出的元素是多少?

题解:(参考:http://blog.csdn.net/queuelovestack/article/details/52164782

关键是merge操作,如果重新再操作一次序列复杂度太高。这个合并起来的 应该一直是保存的,为merge操作准备。我们可以用一个数组来模拟。用两个指针来指向a和b分栈顶元素。用一个pre[]数组来记录每个位置的前驱。

每次push操作,在数组后面添加元素,移动相应指针。

每次merge操作,如merge A B ,将A指针指向a,b指针较高的一个,B指针指向栈底0位置;并将pre[a]=-1,表示该位置前面的数都为一个栈中的值。

每次pop操作,将当前位置标记为已经删除。如果pre值为-1,则一直往前删直到遇到一个没有被删除(执行过弹出操作)的数,否则直接将指针前移即可。

贴上流程(非原创):





代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAX=1e5+10;
int s[MAX],del[MAX];
int pre[MAX];
int a,b,cnt;

int main()
{
//freopen("in.txt","r",stdin);
int cas=1;
int n;
while(scanf("%d",&n)&&n)
{
printf("Case #%d:\n",cas++);
char op[10],ob,oba,obb;
int num;
memset(pre,0xff,sizeof(pre));
memset(del,0,sizeof(del));
int a=0,b=0,cnt=0;
for(int i=0;i<n;i++)
{
scanf("%s",op);
if(op[1]=='u')
{
scanf(" %c %d",&ob,&num);
s[++cnt]=num;
if(ob=='A')
{
pre[cnt]=a;
a=cnt;
}
else
{
pre[cnt]=b;
b=cnt;
}
}
else if(op[1]=='o')
{
scanf(" %c",&ob);
if(ob=='A')
{
printf("%d\n",s[a]);
del[a]=1;
if(pre[a]==-1)
{
do
{
a--;
}while(del[a]==1);
pre[a]=-1;
}
else a=pre[a];
}
else
{
printf("%d\n",s[b]);
del[b]=1;
if(pre[b]==-1)
{
do
{
b--;
}while(del[b]==1);
pre[b]=-1;
}
else b=pre[b];
}
}
else if(op[1]=='e')
{
scanf(" %c %c",&oba,&obb);
if(oba=='A')
{
a=max(a,b);
b=0;
pre[a]=-1;
}
else
{
b=max(a,b);
a=0;
pre[b]=-1;
}
}
}
}
return 0;
}
另外,标程写的简洁到爆啊。

比较简单巧妙的一个做法是引入一个新的栈C,每次合并的时候就把A和B合并到C上,然后把A和B都清空. push还是按正常做,pop注意当遇到要pop的栈为空时,因为题目保证不会对空栈进行pop操作,所以这时应直接改为对C栈进行pop操作. 这样做因为保证每个元素最多只在一次合并中被处理到,pop和push操作当然也是每个元素只做一次,所以总复杂度是O(N)的.

用到一个merge函数:

merge函数的作用是:将两个有序的序列合并为一个有序的序列。

函数参数:merge(first1,last1,first2,last2,result,compare);//firs1t为第一个容器的首迭代器,last1为第一个容器的末迭代器,first2为第二个容器的首迭代器,last2为容器的末迭代器,result为存放结果的容器,comapre为比较函数(可略写,默认为合并为一个升序序列)。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAX=1e5+10;
int x[MAX];
int sta[3][MAX],top[3];

int main()
{
int cas=1;
int n;
while(scanf("%d",&n)&&n)
{
printf("Case #%d:\n",cas++);
char op[10],s[3];
memset(top,0,sizeof(top));
for(int i=0;i<n;i++)
{
scanf("%s %s",op,s);
int ob=s[0]-'A';
if(op[1]=='u')
{
scanf("%d",&x[i]);
sta[ob][++top[ob]]=i;
}
else if(op[1]=='o')
{
if(!top[ob]) ob=2;
printf("%d\n",x[sta[ob][top[ob]--]]);
}
else
{
scanf("%s",s);
top[2]=merge(sta[0]+1,sta[0]+top[0]+1,sta[1]+1,sta[1]+top[1]+1,sta[2]+top[2]+1)-sta[2]-1;
top[0]=top[1]=0;
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐