叉姐的魔法训练(第二课)---- 冰系魔法入门

-----------------------------

一 矩阵相乘

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;
}


-----------------------------

-----------------------------


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值