第十一届北京师范大学程序设计竞赛解题报告
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; }
相关文章推荐
- 组队赛#2解题总结 (BNU 第十一届北京师范大学程序设计竞赛)
- 2014年山东省第五届ACM大学生程序设计竞赛解题报告
- 2015 CQU 重庆大学程序设计竞赛 解题报告
- 第二届华中区程序设计邀请赛暨武汉大学第十一届校赛 网络预选赛 解题报告
- 华东交通大学2014年ACM“双基”程序设计竞赛部分解题报告
- 山东省第四届ACM大学生程序设计竞赛解题报告(部分)
- 2014嘉杰信息杯ACM/ICPC湖南程序设计邀请赛暨第六届湘潭市程序设计竞赛 解题报告
- “光庭杯”第五届华中北区程序设计邀请赛 暨 WHU第八届程序设计竞赛(部分解题报告)
- 华东交通大学2013ACM“双基”程序设计竞赛 解题报告
- 2016年湖南省第十二届大学生计算机程序设计竞赛 解题报告
- 2017广东工业大学程序设计竞赛决赛【解题报告】【待补全】
- UESTC 第五届ACM趣味程序设计竞赛第四场(正式赛) 解题报告
- UESTC-第五届ACM趣味程序设计竞赛第四场(正式赛)--不完全解题报告
- 浙江省第6届大学生程序设计竞赛解题报告
- 河南省第七届ACM大学生程序设计竞赛 解题报告
- UESTC 第五届ACM趣味程序设计竞赛第一场(热身赛,非原创题) 解题报告
- 2013级新生程序设计基础竞赛-正式赛 F 异或最大值 解题报告
- 2015 中国大学生程序设计竞赛解题报告
- 2016年第四届湘潭大学新生趣味程序设计竞赛 解题报告(动态规划)
- UESTC-第五届ACM趣味程序设计竞赛第四场(正式赛)--不完全解题报告