叉姐的魔法训练(第二课)---- 冰系魔法入门
-----------------------------
一 矩阵相乘
POJ 3213 PM 3
给出三个矩阵A(NP)、B(PM)、C(NM) N,P,M<1000
C=A*B,但是矩阵C中有可能有一个元素的值是错误的。
问哪一个元素是错的,并求出正确的值。
直接暴力求出C的话O(n^3)必然会超时
注意矩阵乘法的公式
用sumB[i]表示矩阵B第i行所有元素的和,sumC[i]表示矩阵C第i行所有元素的和。
则 sumC[i] = ∑ A[i][k]*sumB[k] ,若理论值与计算值不等,则说明矩阵C第i行的元素出错。
接下来只要枚举计算矩阵C第i行的每个元素找到错解即可。
总复杂度仅有O(n^2)
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long LL; const int maxn=1011; int N,P,M; int A[maxn][maxn],B[maxn][maxn]; LL C[maxn][maxn]; LL sumB[maxn],sumC[maxn]; int wr,wl; LL rt; int main() { while (~scanf("%d%d%d",&N,&P,&M)){ for (int i=1;i<=N;i++){ for (int j=1;j<=P;j++){ scanf("%d",&A[i][j]); } } memset(sumB,0,sizeof(sumB)); for (int i=1;i<=P;i++){ for (int j=1;j<=M;j++){ scanf("%d",&B[i][j]); sumB[i]+=B[i][j]; } } memset(sumC,0,sizeof(sumC)); for (int i=1;i<=N;i++){ for (int j=1;j<=M;j++){ scanf("%I64d",&C[i][j]); sumC[i]+=C[i][j]; } } //puts("Done."); wr=-1; for (int i=1;i<=N;i++){ LL sum=0; for (int j=1;j<=P;j++){ sum+=A[i][j]*sumB[j]; } if (sum!=sumC[i]){ wr=i; break; } } if (wr==-1) puts("Yes"); else{ puts("No"); for (int i=1;i<=M;i++){ LL sum=0; for (int j=1;j<=P;j++){ sum+=A[wr][j]*B[j][i]; } if (sum!=C[wr][i]){ wl=i; rt=sum; break; } } printf("%d %d\n",wr,wl); printf("%I64d\n",rt); } } return 0; }
-----------------------------
二 时光倒流
POJ 3465 Battle
与敌人战斗n回合,每回合对敌人造成x点伤害,或防御敌人所有伤害,或恢复y点生命。自身生命值为H1,敌人生命值为H2。
生命小于等于0则死亡,n回合后也会死亡。若能赢,输出最小回合数。若必输,输出最大伤害数。
只要不会死,每回合都贪心攻击。若生命减为0以下,则改写过去某一回合,要求恢复最多的生命,用优先队列维护。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> using namespace std; const int maxn=211111; int n,x,y,h1,h2; int a[maxn]; priority_queue<int>que; int main() { while (~scanf("%d%d%d%d%d",&n,&x,&y,&h1,&h2)){ while (!que.empty()) que.pop(); for (int i=1;i<=n;i++){ scanf("%d",&a[i]); } int i,hit=0,mhit=0; for (i=1;i<=n;i++){ hit++; mhit=max(hit,mhit); if (hit*x>=h2) break; h1-=a[i]; que.push(max(a[i],y)); while (!que.empty()&&h1<=0){ int up=que.top(); que.pop(); h1+=up; hit--; } } if (i<=n){ printf("Win\n%d\n",i); } else{ printf("Lose\n%d\n",mhit*x); } } return 0; }
-----------------------------
三 凸包本质
POJ 2595 Min-Max
//题意与题解:
题意:设函数F(x1,x2...xn)=Σuixi(1<=i<=n),u为函数固定的系数,且对u有限制Σu=1且u∈[0,1],但是你不知道,你只知道一组输入x1,x2...xn对应的输出为C,问题是给定的另一组输入y1,y2...yn的输出最小与最大可能是多少。(冰封寒月)
观察一下u的神奇范围我们可以很直观的联想到一群质点的重心公式,不妨将(xi,yi)作为坐标放在平面直角坐标系中,我们就可以将所有的有序实数对看成质量相等的质点,C就是其重心的x坐标,答案即为重心的y坐标,由重心知识可知重心位于点集的凸包内部,所以贪心得到答案为凸包边(点)上,所以求出凸包维护一下答案就行了。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int maxn=61111; const double OO=1e50; struct Point{ int x,y; void output(){ printf("%d %d\n",x,y); } }p[maxn]; int n; Point MinA; Point stack[maxn]; int top; double cross(Point A,Point B,Point C){ return (B.x-A.x)*(C.y-A.y)-(B.y-A.y)*(C.x-A.x); } double dist(Point A,Point B){ return hypot(A.x-B.x,A.y-B.y); } bool cmp(Point A,Point B) { double k=cross(MinA,A,B); if(k<0) return 0; if(k>0) return 1; return dist(MinA,A)<dist(MinA,B); } void Graham(Point p[],int n) { for(int i=1;i<n;i++) if(p[i].y<p[0].y||(p[i].y==p[0].y&&p[i].x<p[0].x)) swap(p[i],p[0]); MinA=p[0]; p[n]=p[0]; sort(p+1,p+n,cmp); stack[0]=p[0]; stack[1]=p[1]; top=2; for(int i=2;i<n;i++){ while(top>=2&&cross(stack[top-2],stack[top-1],p[i])<=0) top--; stack[top++]=p[i]; } } int c; double minn,maxx; void check(Point a,Point b){ if (a.x>b.x) swap(a,b); if (a.x<=c&&b.x>=c){ if (a.x==c&&b.x==c){ maxx=max(maxx,(double)max(a.y,b.y)); minn=min(minn,(double)min(a.y,b.y)); } else{ double k=((double)c-a.x)/((double)b.x-a.x)*(b.y-a.y)+a.y; maxx=max(maxx,k); minn=min(minn,k); } } } int main() { while (~scanf("%d%d",&n,&c)){ for (int i=0;i<n;i++) scanf("%d",&p[i].x); for (int i=0;i<n;i++) scanf("%d",&p[i].y); if (n==1){ printf("%0.3f %0.3f\n",(double)p[0].y,(double)p[0].y); continue; } Graham(p,n); minn=OO,maxx=-OO; //for (int i=0;i<top;i++) stack[i].output(); stack[top]=stack[0]; for (int i=1;i<=top;i++){ check(stack[i-1],stack[i]); } printf("%0.3f %0.3f\n",minn,maxx); } return 0; }
-----------------------------
-----------------------------