山东省第四届ACM大学生程序设计竞赛解题报告(部分)
2013年"浪潮杯"山东省第四届ACM大学生程序设计竞赛排名:http://acm.upc.edu.cn/ranklist/
一、第J题坑爹大水题,模拟一下就行了
J:Contest Print Server
【题解】:
题目大意:输入 n,s,x,y,mod 分别队伍数n,还有一个s生成函数 s=((s*x)+y)%mod,就是打印机根据要求打印纸张,打印到s时,打印机将重置,生成新的s
【code】:
1 #include <iostream> 2 #include <cstdio> 3 #include <string.h> 4 using namespace std; 5 6 int main() 7 { 8 int t; 9 scanf("%d",&t); 10 while(t--) 11 { 12 int n,s,x,y,mod,i,p; 13 char team[30],str[20]; 14 int cnt = 0; 15 scanf("%d%d%d%d%d",&n,&s,&x,&y,&mod); 16 for(i=0;i<n;i++) 17 { 18 scanf("%s%s%d%s",team,str,&p,str); 19 while(1) 20 { 21 if(p<=s-cnt) 22 { 23 cnt+=p; 24 printf("%d pages for %s\n",p,team); 25 break; 26 } 27 else 28 { 29 printf("%d pages for %s\n",s-cnt,team); 30 s = ((s*x)+y)%mod; 31 cnt = 0; 32 } 33 } 34 } 35 putchar(10); 36 } 37 return 0; 38 }
二、第I题概率DP问题
I:The number of steps
【题解】:
1
/ \
2 — 3
/ \ / \
4 — 5 — 6
输入概率:a b c d e 分别表示:
例如:
1
a/ \b 只有左右孩子的就是概率a、b
c — 3
d / \e 有左右孩子并且有左兄弟 概率分别为 c、d、e
— 5 如果只有左兄弟的话概率为 1
只有以上这三种情况:
如果f(i)表示第i步达到目的地的概率的话
结果ans = f(1)*1 + f(2)*2 + f(3)*3 + ....+f(n)*n
【code】:
1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 6 double dp[100][50][50]; 7 int main() 8 { 9 int n; 10 while(~scanf("%d",&n)&&n) 11 { 12 double a,b,c,d,e; 13 scanf("%lf%lf%lf%lf%lf",&a,&b,&c,&d,&e); 14 memset(dp,0,sizeof(dp)); 15 dp[0][1][1] = 1; 16 int i,j,k; 17 for(k=1;k<=(n-1)*2;k++) 18 { 19 for(i=1;i<=n;i++) 20 { 21 for(j=1;j<=i;j++) 22 { 23 if(j-1<1&&i+1<=n&&j+1<=n) 24 { 25 dp[k][i+1][j] += dp[k-1][i][j]*a; 26 dp[k][i+1][j+1] += dp[k-1][i][j]*b; 27 } 28 else if(j-1>=1&&i+1<=n&&j+1<=n) 29 { 30 dp[k][i][j-1] += dp[k-1][i][j]*e; 31 dp[k][i+1][j] += dp[k-1][i][j]*c; 32 dp[k][i+1][j+1] += dp[k-1][i][j]*d; 33 } 34 else if(j-1>=1&&i==n) 35 { 36 dp[k][i][j-1] += dp[k-1][i][j]; 37 } 38 } 39 } 40 } 41 double res = 0; 42 for(i=1;i<=2*(n-1);i++) 43 { 44 res+=dp[i][n][1]*i; 45 } 46 printf("%.2lf\n",res); 47 } 48 return 0; 49 }
三、第A题,向量旋转
A - Problem A:Rescue The Princess
【题解】:
给你平面上两个点A、B求点C,是的A、B、C逆时针成等边三角形
向量的旋转:
【code1】:
1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 6 double xx1,yy1,xx2,yy2; 7 8 int main() 9 { 10 int T; 11 scanf("%d",&T); 12 while (T--) 13 { 14 scanf("%lf%lf%lf%lf",&xx1,&yy1,&xx2,&yy2); 15 double tx = xx2 - xx1; 16 double ty = yy2 - yy1; 17 18 double x = tx*(1.0/2.0) - ty*(sqrt(3.0)/2.0) + xx1; 19 double y = ty*(1.0/2.0) + tx*(sqrt(3.0)/2.0) + yy1; 20 printf("(%.2lf,%.2lf)\n",x,y); 21 } 22 return 0; 23 }
不会向量旋转,直接解方程方法做:
【code2】:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #define exb 1e-6 6 #define PI acos(-1.0) 7 using namespace std; 8 struct node 9 { 10 double x,y; 11 }; 12 13 14 double judge(node a ,node b) 15 { 16 return (a.x*b.y-a.y*b.x); 17 } 18 19 double dist(double x1,double y1,double x2,double y2) 20 { 21 return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); 22 } 23 24 int main() 25 { 26 int t; 27 scanf("%d",&t); 28 while(t--) 29 { 30 double x1,y1,x2,y2; 31 scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); 32 double xx=(x1+x2)/2.0; 33 double yy=(y1+y2)/2.0; 34 double dd=dist(x1,y1,x2,y2); 35 if(fabs(y1-y2)<exb) 36 { 37 double yy1=y1+dd*sin(PI/3.0); 38 double yy2=y1-dd*sin(PI/3.0); 39 node ab,ac; 40 ab.x=x2-x1; 41 ab.y=y2-y1; 42 ac.x=xx-x1; 43 ac.y=yy1-y1; 44 45 if(judge(ab,ac)>0) 46 { 47 printf("(%.2f,%.2f)\n",xx,yy1); 48 } 49 else 50 { 51 printf("(%.2f,%.2f)\n",xx,yy2); 52 } 53 } 54 else 55 { 56 if(fabs(x1-x2)<exb) 57 { 58 double xx1=x1+dd*sin(PI/3.0); 59 double xx2=x1-dd*sin(PI/3.0); 60 node ab,ac; 61 ab.x=x2-x1; 62 ab.y=y2-y1; 63 ac.x=xx1-x1; 64 ac.y=yy-y1; 65 if(judge(ab,ac)>0) 66 { 67 printf("(%.2f,%.2f)\n",xx1,yy); 68 } 69 else 70 { 71 printf("(%.2f,%.2f)\n",xx2,yy); 72 } 73 } 74 else 75 { 76 double k=-(x1-x2)/(y1-y2); 77 double pp=atan(k); 78 if(pp>PI/2.0) 79 pp=PI-pp; 80 k=tan(pp); 81 double b=yy-(k*xx); 82 double dd1=dd*sin(PI/3.0); 83 double xx1=sqrt(dd1*dd1/(k*k+1.0)); 84 double yy1=k*xx1; 85 double xx2=-sqrt(dd1*dd1/(k*k+1.0)); 86 double yy2=k*xx2; 87 node ab,ac; 88 ab.x=x2-x1; 89 ab.y=y2-y1; 90 ac.x=xx+xx1-x1; 91 ac.y=yy+yy1-y1; 92 if(judge(ab,ac)>0) 93 { 94 printf("(%.2f,%.2f)\n",xx+xx1,yy+yy1); 95 } 96 else 97 printf("(%.2f,%.2f)\n",xx+xx2,yy+yy2); 98 } 99 } 100 } 101 return 0; 102 }
四、第B题,听说可以暴力BFS过,我们队用的 强连通分量+缩点重构图+拓扑排序
Problem B:Thrall’s Dream
【题解】:
给定n个点,m条有向边,求解任意两点是否可达。也就是 u->v or v->u 问题
【code】:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #define N 2005 5 #define M 10005 6 using namespace std; 7 struct edges 8 { 9 int u,v,next; 10 }; 11 edges mye[M]; 12 edges cj[M]; 13 int head[N]; 14 int myhead[N]; 15 int cnt; 16 int cntcnt; 17 int cc,gg; 18 int dfn[N],low[N],Belong[N],Stap[N]; 19 bool ff[N]; 20 int visitNum,ct,Stop; 21 bool flag[N]; 22 int id[N],od[N]; 23 void addEdge(int x,int y) 24 { 25 mye[cnt].u=x; 26 mye[cnt].v=y; 27 mye[cnt].next=head[x]; 28 head[x]=cnt++; 29 } 30 31 void Add(int x,int y) 32 { 33 cj[cntcnt].u=x; 34 cj[cntcnt].v=y; 35 cj[cntcnt].next=myhead[x]; 36 myhead[x]=cntcnt++; 37 } 38 39 int n,m; 40 void init() 41 { 42 scanf("%d%d",&n,&m); 43 memset(head,-1,sizeof(head)); 44 memset(myhead,-1,sizeof(myhead)); 45 cnt=1; 46 cntcnt=1; 47 for(int i=0;i<m;i++) 48 { 49 int x,y; 50 scanf("%d%d",&x,&y); 51 addEdge(x,y); 52 } 53 memset(dfn,0,sizeof(dfn)); 54 memset(low,0,sizeof(low)); 55 memset(Belong,0,sizeof(Belong)); 56 memset(Stap,0,sizeof(Stap)); 57 memset(flag,false,sizeof(flag)); 58 memset(id,0,sizeof(id)); 59 memset(od,0,sizeof(od)); 60 61 } 62 63 void tarjan(int i) 64 { 65 int y; 66 Stap[++Stop]=i; 67 flag[i]=true; 68 dfn[i]=low[i]=++visitNum; 69 for(int j=head[i];j!=-1;j=mye[j].next) 70 { 71 y=mye[j].v; 72 if(!dfn[y]) 73 { 74 flag[y]=true; 75 tarjan(y); 76 low[i]=min(low[i],low[y]); 77 } 78 else if(flag[y]) 79 low[i]=min(low[i],dfn[y]); 80 } 81 if(low[i]==dfn[i]) 82 { 83 ct++; 84 do 85 { 86 y=Stap[Stop--]; 87 Belong[y]=ct; 88 flag[y]=false; 89 }while(y!=i); 90 } 91 } 92 93 void dfs(int x,int len) 94 { 95 if(myhead[x]==-1 || len>=ct) 96 { 97 if(len>gg) 98 gg=len; 99 return; 100 } 101 for(int i=myhead[x];i!=-1;i=cj[i].next) 102 { 103 int y=cj[i].v; 104 if(!ff[y]) 105 { 106 ff[y]=true; 107 dfs(y,len+1); 108 ff[y]=false; 109 } 110 } 111 } 112 void solve() 113 { 114 visitNum=ct=Stop=0; 115 for(int i=1;i<=n;i++) 116 { 117 if(!dfn[i]) 118 tarjan(i); 119 } 120 if(ct==1) 121 { 122 printf("Case %d: Kalimdor is just ahead\n",cc++); 123 return; 124 } 125 for(int i=1;i<=n;i++) 126 { 127 for(int j=head[i];j!=-1;j=mye[j].next) 128 { 129 int y=mye[j].v; 130 int u=Belong[i]; 131 int v=Belong[y]; 132 if(u!=v) 133 { 134 od[u]++; 135 id[v]++; 136 Add(u,v); 137 } 138 } 139 } 140 int ans1=0,ans2=0; 141 int temp=0; 142 for(int i=1;i<=ct;i++) 143 { 144 if(od[i]==0) 145 { 146 ans1++; 147 } 148 if(id[i]==0) 149 { 150 ans2++; 151 temp=i; 152 } 153 } 154 if(ans1>1 || ans2>1) 155 { 156 printf("Case %d: The Burning Shadow consume us all\n",cc++); 157 return; 158 } 159 memset(ff,false,sizeof(ff)); 160 gg=0; 161 dfs(temp,1); 162 if(gg!=ct) 163 { 164 printf("Case %d: The Burning Shadow consume us all\n",cc++); 165 166 } 167 else 168 { 169 printf("Case %d: Kalimdor is just ahead\n",cc++); 170 } 171 return; 172 } 173 int main() 174 { 175 int t; 176 scanf("%d",&t); 177 cc=1; 178 while(t--) 179 { 180 init(); 181 solve(); 182 } 183 return 0; 184 }
五、F题
Problem F:Alice and Bob
【题解】:
给出一个多项式:(a0*x^(2^0)+1) * (a1 * x^(2^1)+1)*.......*(an-1 * x^(2^(n-1))+1)
输入P,求X^p 前边的系数。
【code】:
1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 int a[10086]; 6 int main() 7 { 8 long long sb,p; 9 int t; 10 int n; 11 int q; 12 while(scanf("%d",&t)!=EOF) 13 { 14 while(t--) 15 { 16 scanf("%d",&n); 17 int i; 18 for(i=0;i<n;i++) 19 { 20 scanf("%d",&a[i]); 21 } 22 scanf("%d",&q); 23 while(q--) 24 { 25 scanf("%lld",&p); 26 long long sb=1; 27 for(i=0;i<n&&p!=0;i++) 28 { 29 if(p%2==1) 30 { 31 sb*=a[i]; 32 sb%=2012; 33 } 34 p/=2; 35 } 36 if(p==0) 37 printf("%lld\n",sb); 38 else 39 printf("0\n"); 40 } 41 } 42 } 43 return 0; 44 }
六:E题
Problem E:Mountain Subsequences
【code】:
1 #include <iostream> 2 #include <cstdio> 3 #include <string.h> 4 using namespace std; 5 char sb[100086]; 6 int dp[100086]; 7 int ha[30]; 8 int main() 9 { 10 int n; 11 while(scanf("%d",&n)!=EOF) 12 { 13 int i,j,x; 14 long long max,s; 15 scanf("%s",sb); 16 memset(ha,0,sizeof(ha)); 17 for(i=0;i<n;i++) 18 { 19 x=sb[i]-'a'; 20 dp[i]=0; 21 for(j=0;j<x;j++) 22 { 23 dp[i]+=ha[j]; 24 dp[i]%=2012; 25 } 26 ha[x]+=dp[i]+1; 27 ha[x]%=2012; 28 } 29 /* for(i=n-1;i>=0;i--) 30 { 31 printf("%lld ",dp[i]); 32 }*/ 33 // printf("\n"); 34 max=0; 35 memset(ha,0,sizeof(ha)); 36 for(i=n-1;i>=0;i--) 37 { 38 x=sb[i]-'a'; 39 s=0; 40 for(j=0;j<x;j++) 41 { 42 s+=ha[j]; 43 s%=2012; 44 } 45 ha[x]+=s+1; 46 ha[x]%=2012; 47 max+=s*dp[i]; 48 max%=2012; 49 // printf("%lld ",s); 50 } 51 //printf("\n"); 52 printf("%lld\n",max); 53 } 54 return 0; 55 }
七、H题
Problem H:Boring Counting