您的位置:首页 > 其它

第十一届北京师范大学程序设计竞赛解题报告

2013-04-30 21:42 267 查看
 

 A题:模拟

#include<stdio.h>
#include<string.h>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
int i,n,cas;
vector <string> month[15];
month[11].push_back("Basic Training");
month[12].push_back("Basic Training");
month[12].push_back("Rookie Contest");
for(i=2;i<=4;i++) month[i].push_back("Spring Training");
month[4].push_back("BNU Contest");
month[7].push_back("Practice Week");
for(i=7;i<=8;i++) month[i].push_back("Summer Training");
for(i=9;i<=11;i++) month[i].push_back("Regional Contest");
scanf("%d",&cas);
while(cas--)
{
scanf("%d",&n);
if(month
.size()) {
for(i=0;i<month
.size();i++)
printf("%s\n",month
[i].c_str());
}else printf("Unknown\n");
}
return 0;
}


 

B题:背包,二分都可以,背包的代码如下

#include<stdio.h>
#include<string.h>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
int dp[5][1100];
int main()
{
int cas,L,x,n,i,j,k,v;
scanf("%d",&cas);
while(cas--){
scanf("%d%d%d",&L,&x,&n);
L-=x; memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(i=1;i<=n;i++)
{
scanf("%d",&v);
for(k=0;k<4;k++)
for(j=L-v;j>=0;j--)
if(dp[k][j]) dp[k+1][j+v]=1;
}
puts(dp[4][L]?"Yes":"No");
}
return 0;
}


C题:直接暴力搜索必胜点,必败点;

#include<stdio.h>
#include<string.h>
#include<string>
#include<map>
#include<algorithm>
#include<vector>

using namespace std;
int dfs(int L,int H)
{
if(L==1&&H==1) return 0;
if(L%2==0&&dfs(L/2,H)==0)
return 1;
if(H%2==0&&dfs(L,H/2)==0)
return 1;
return 0;
}
int main()
{
int cas,L,H;
scanf("%d",&cas);
while(cas--){
scanf("%d%d",&L,&H);
puts(dfs(L,H)?"Adidas loses":"Adivon prevails");
}
return 0;
}


 

D题:构造trie树,找分叉点并统计,用所有的分叉点统计值求和就是答案;

#include<stdio.h>
#include<string.h>
#include<string>
#include<map>
#include<set>
#include<algorithm>
#include<vector>
using namespace std;
#define N 210000
int ch
[26];
long long ant,val
;

int newnode(){
int i;++ant;
for(i=0;i<26;i++)
ch[ant][i]=0;
val[ant]=0;
return ant;
}
void insert(char *str)
{
int idx,i,rt=0;
val[rt]++;
for(i=0;str[i];i++)
{
idx=str[i]-'a';
if(!ch[rt][idx]) ch[rt][idx]=newnode();
rt=ch[rt][idx];
val[rt]++;
}
}
long long ans;
void make(int rt)
{
int i;
long long t;
for(i=0;i<26;i++){
if(ch[rt][i]){
make(ch[rt][i]);
t=val[0]-val[ch[rt][i]];
t*=val[ch[rt][i]];
ans+=t;
}
}
}
char str[110000];
int main()
{
int cas,i,j,L,n;
scanf("%d",&cas);
while(cas--)
{
ant=-1;newnode();
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%s",str);
L=strlen(str);
insert(str);
for(j=0;j<L/2;j++)
swap(str[j],str[L-j-1]);
insert(str);
}
ans=0;make(0);
printf("%lld\n",ans);
}
return 0;
}

直接模拟统计的版本:

#include<stdio.h>
#include<string.h>
#include<string>
#include<map>
#include<set>
#include<algorithm>
#include<vector>
using namespace std;

#define N 210000

int ch
[26],flag
;
long long ant,val
,sum
,ans;

int newnode(){
int i;++ant;
for(i=0;i<26;i++)
ch[ant][i]=0;
val[ant]=0;flag[ant]=0;
return ant;
}
void insert(char *str)
{
int idx,i,rt=0;
val[rt]++;
for(i=0;str[i];i++)
{
idx=str[i]-'a';
if(!ch[rt][idx]) ch[rt][idx]=newnode();
rt=ch[rt][idx];
val[rt]++;
}
flag[rt]++;
}
void make(int rt)
{
int i;
sum[rt]=0;
for(i=0;i<26;i++){
if(ch[rt][i]){
make(ch[rt][i]);
sum[rt]+=sum[ch[rt][i]]+val[ch[rt][i]];
}
}
for(i=0;i<26;i++){
if(ch[rt][i]){
ans+=val[ch[rt][i]]*(sum[rt]-sum[ch[rt][i]]-val[ch[rt][i]]);
if(flag[ch[rt][i]])ans+=sum[ch[rt][i]]*flag[ch[rt][i]];
}
}
}
char str[110000];
int main()
{
int cas,i,j,L,n;
scanf("%d",&cas);
while(cas--)
{
ant=-1;newnode();
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%s",str);
L=strlen(str);
insert(str);
for(j=0;j<L/2;j++)
swap(str[j],str[L-j-1]);
insert(str);
}
ans=0;make(0);
printf("%lld\n",ans);
}
return 0;
}


 

 

E题:不会弄

 

F题:比赛的时候没弄出来,赛后看了别人的才弄出来,大概思路是:

设last表示在当前点可获得的分的期望值,则下一点可获得的分的期望值就是last=(last+1)*p

最后把所有点上获得的分加起来就是答案;

 

G题:不会弄

 

H题:求出公平决策事件发生的概率p,最后决策事件发生的期望次数就是1/p;

#include<stdio.h>
#include<string.h>
#include<string>
#include<algorithm>
#include<vector>

using namespace std;
int main()
{
int cas;
double p;
scanf("%d",&cas);
while(cas--){
scanf("%lf",&p);
printf("%.2lf\n",1.0/(p*(1-p)));
}
return 0;
}


 

I题:和逆元的性质有关,因为除以一个数就等于乘以一个数的逆元,b[i]=(a[i]*w)%m且v是w模m的逆;

所以a[i]=(b[i]*v)%m;也就有s*v=sum{ (a[i]*x[i]) }%m; 又因为a[i]>2*a[i-1],下面的过程就和二进制分解一样了,把所有的x[i]待定出来就可以了;

 

 

J题:鸣人的查克拉

题目链接:http://acm.bnu.edu.cn/bnuoj/contest_show.php?cid=1605#problem/17964

 题目大意:

  鸣人发明了一种忍术,可以在短时间内提高查克拉。

  如果在某个时刻发动这个忍术,鸣人需要先消耗该时刻的查克拉值;

  在某个时候结束这个忍术,鸣人能获得该时刻的查克拉值(忍术必须先发动才能结束)

  如果某时刻鸣人具有的查克拉值少于该时刻的查克拉值,那么鸣人是不能发动该忍术的;

  鸣人知道了自己的查克拉的初始值,以及各个时刻的查克拉值,如果他最多可以发动两次

  该忍术(他也可以选择发动一次或者不发动),那么他最多能达到的查克拉值是多少?

 

  解题思路:

  

   我们令前一次发动忍术获得的查克拉为k,把只发动一次也看着两次(就当前一次获得的查克拉为零);

  这样我们就要维护k值,设当前时间为i,查克拉为A[i],前一段时间可以使用忍术需且需要消耗的查克拉

  最小值为Min,则如果当前时间结束忍术的话可以获得A[i]-Min的查克拉,这样我们就可以用A[i]-Min去更新k值

  得到1->i区间里如果发动一次忍术获得的查克拉的最大值k,如果当前可以发动第一次查克拉且当前的值比Min小,

  更新Min值;

  

   知道了求发动一次忍术可以获得的最大查克拉值,我们考虑构造发动第二次忍术,假设当前时间为i,且区间(1,i-1)

  里发动一次忍术获得的查克拉最大值为k(前面已经介绍过求法),且当前时间点可以再次发动,令m=k-A[i]表示第二次使用

  忍术后的剩下的查克拉,并维护m的最大值;

   设当前时间为i,使用两次忍术后得到的查克拉最大值为t,且区间(1,i-1)里面发动第二次忍术后剩下的查克拉最大值为m(上面介绍过),

  则当前点结束第二次忍术可以获得的查拉值为m+A[i],并更新t值。最后的t值就是答案。

 

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
using namespace std;
int A[11000];
int main()
{
int i,c,n,Min,k,t,g,m;
while(scanf("%d%d",&c,&n)!=EOF)
{
k=t=0;g=c;
m=-1000000;
Min=1000000;
for(i=1;i<=n;i++)
{
scanf("%d",&A[i]);
t=max(t,m+A[i]);
if(g>=A[i]){
Min=min(Min,A[i]);
m=max(m,k-A[i]);
}
k=max(k,A[i]-Min);
g=max(g,k+c);
}
printf("%d\n",c+t);
}
return 0;
}


K题: 用邻接矩阵存储转移关系,因为一点到达另一点的概率是路劲上所有概率之积,这种情况和图论中走n步,一个点到另一个点的路劲条数的求法一样;

所以把一列之间的转移关系表示成一个邻接矩阵,这样就可以用解决图论中求路劲条数的方法来求了,也就是矩阵自乘n次,可以用矩阵快速幂发优化一下乘法,

代码如下:

#include<stdio.h>
#include<string.h>

int n;
struct mat{
double M[30][30];
mat(double v=0.0){
for(int i=0;i<30;i++)
for(int j=0;j<30;j++)
if(i==j) M[i][j]=v;else M[i][j]=0;
}
mat operator*(const mat &tem) const
{
int i,j,k; mat tmp(0);
for(i=0;i<n;i++)
for(j=0;j<n;j++)
for(k=0;k<n;k++)
tmp.M[i][j]+=M[i][k]*tem.M[k][j];
return tmp;
}
};
mat power(mat x,int y)
{
mat sum(1);
while(y){
if(y&1) sum=sum*x;
x=x*x;y>>=1;
}return sum;
}

int main()
{
int cas,m,k,s,i;
scanf("%d",&cas);
while(cas--){
scanf("%d%d%d%d",&n,&m,&k,&s);
mat ans(0);
if(n==1){ printf("1.0000\n"); continue; }
for(i=0;i<n;i++){
if(i>0) ans.M[i][i-1]=0.5;
if(i<n-1) ans.M[i][i+1]=0.5;
}
ans.M[0][1]=ans.M[n-1][n-2]=1.0;
ans=power(ans,m*k);
for(i=0;i<n-1;i++)printf("%.4lf ",ans.M[s-1][i]);
printf("%.4lf\n",ans.M[s-1][n-1]);
}
return 0;
}

 

H题:先解出两个交点,最后就是判断和那两条边交,并计算出一边的面积,最后输出最小面积就好了,代码写的很搓。。。。。

#include<stdio.h>
#include<string.h>
#include<string>
#include<math.h>
#include<map>
#include<set>
#include<algorithm>
#include<vector>
using namespace std;

int judge(double a,double b,double c,double x1,double y1,double x2,double y2,double &x,double &y)
{
if(x1==x2){
if(b){
y=(a*x1+c)/(-b);
x=x1;
if(y>y2||y<y1) return 0;
return 1;
}
else return 0;
}
else{
if(a){
x=(b*y1+c)/(-a);
y=y1;
if(x>x2||x<x1) return 0;
return 1;
}
else return 0;
}
}
struct node
{
double x,y;
}num[10];

bool cmp(node a,node b)
{
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
int main()
{
int cas;
double x1,x2,y1,y2,a,b,c,ans,sum;
scanf("%d",&cas);
while(cas--){
scanf("%lf%lf%lf%lf%lf%lf%lf",&x1,&y1,&x2,&y2,&a,&b,&c);
sum=(x2-x1)*(y2-y1);
if(judge(a,b,c,x1,y2,x2,y2,num[0].x,num[0].y)&&judge(a,b,c,x1,y1,x2,y1,num[1].x,num[1].y))
{
ans=(num[0].x+num[1].x-2*x1)*(y2-y1)/2;
}
else if(judge(a,b,c,x1,y1,x1,y2,num[0].x,num[0].y)&&judge(a,b,c,x2,y1,x2,y2,num[1].x,num[1].y))
{
ans=(num[0].y+num[1].y-y1*2)*(x2-x1)/2;
}
else if(judge(a,b,c,x1,y1,x1,y2,num[0].x,num[0].y)&&judge(a,b,c,x1,y2,x2,y2,num[1].x,num[1].y))
{
ans=(num[1].x-num[0].x)*(num[1].y-num[0].y)/2;
}
else if(judge(a,b,c,x1,y1,x1,y2,num[0].x,num[0].y)&&judge(a,b,c,x1,y1,x2,y1,num[1].x,num[1].y))
{
ans=(num[1].x-num[0].x)*(num[0].y-num[1].y)/2;
}
else if(judge(a,b,c,x1,y1,x2,y1,num[0].x,num[0].y)&&judge(a,b,c,x2,y1,x2,y2,num[1].x,num[1].y))
{
ans=(num[1].x-num[0].x)*(num[1].y-num[0].y)/2;
}
else if(judge(a,b,c,x2,y1,x2,y2,num[0].x,num[0].y)&&judge(a,b,c,x1,y2,x2,y2,num[1].x,num[1].y))
{
ans=(num[1].x-num[0].x)*(num[0].y-num[1].y)/2;
}
if(sum-ans<ans) ans=sum-ans;
printf("%.3lf\n",ans);
}
return 0;
}


 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐