叉姐的魔法训练(二)

POJ - 3213 PM3
题意就是矩阵乘法有一个数出错了,请你找到他并且把争取的一输出就行。
首先如果暴力的话肯定是O(N^3)的,就不考虑暴力了,至于碰运气的随机化题主交了几次之后就放弃了。
正解是这样的,如果结果矩阵中 Cij C i j 是错误的,那么想办法要把暴力的做法先优化掉一维,我们可以发现矩阵C中第i行的和,我们设为sumC[i],和矩阵B中第i行的和,我们设为sumB[i],满足以下关系

sumCij=i=1nAijsumBj s u m C i j = ∑ i = 1 n A i j ∗ s u m B j

既然有一个错误的,那么公式算出来的值有何实际的值必然是不一样的,那么我们就将范围缩小到了一行,就能在O(N^2)时间内解决这个问题了

#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
const int maxn = 1005;
ll a[maxn][maxn],b[maxn][maxn],c[maxn][maxn];
ll sumb[maxn],sumc[maxn];
int n,m,p;
ll check(int x,int y)
{
    ll ans = 0;
    for(int k = 1;k<=p;k++)
    {
        ans += a[x][k] * b[k][y];
    }
    return ans;
}
int main()
{

    while(scanf("%d%d%d",&n,&p,&m) != EOF)
    {
        mem(sumb);
        mem(sumc);
        for(int i = 1;i<=n;i++)
        {
            for(int j = 1;j<=p;j++)
            {
                scanf("%I64d",&a[i][j]);
            }
        }

        for(int i = 1;i<=p;i++)
        {
            for(int j = 1;j<=m;j++)
            {
                scanf("%I64d",&b[i][j]);
                sumb[i] += b[i][j];
            }
        }

        for(int i =1;i<=n;i++)
        {
            for(int j = 1;j<=m;j++)
            {
                scanf("%I64d",&c[i][j]);
                sumc[i] += c[i][j];
            }
        }
        int x = 0;
        for(int i =1;i<=n;i++)
        {
            ll temp = 0;
            for(int j = 1;j<=p;j++)
            {
                temp += a[i][j] * sumb[j];
            }
            if(temp != sumc[i])
            {
                x = i;
                break;
            }
        }
        if(x == 0)
        {
            printf("Yes\n");
        }
        else
        {
            for(int j = 1;j<=m;j++)
            {
                ll temp = check(x,j);
                if(temp != c[x][j])
                {
                    printf("No\n%d %d\n%I64d\n",x,j,temp);
                    break;
                }
            }
        }
    }

    return 0;
}

POJ - 3465 Battle

题目大意是,勇者和龙作战,各有h1,h2滴血,每次勇者可以选择对龙造成x点伤害,回避龙的攻击,治疗自己y的血,之后龙攻击勇者,每回合龙造成的伤害不一样,问能否击败龙,能的话输出用的回合数,不能的话输出能给龙造成的最高伤害。
我们首先贪心地去想,如果能攻击那我们尽量攻击,如果不能攻击龙,就说明我们之前的攻击需要被替换成治疗或者回避,那我们记录每次攻击后的血量或者治疗量的最大值,放入优先队列,每次死亡的时候就把能回血最多的那次攻击取消。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
const int maxn = 100050;
int n,x,y,h1,h2;
int a[maxn];
int ans,flag,round;
int main()
{


    while(scanf("%d%d%d%d%d",&n,&x,&y,&h1,&h2) != EOF)
    {
        for(int i = 1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        int i;
        int cnt = 0;
        int max_cnt = 0;
        priority_queue<int> q;
        for(i =1;i<=n;i++)
        {
            cnt++;
            if(cnt * x >= h2)
            {
                break;
            }
            max_cnt = max(max_cnt,cnt);
            h1 -= a[i];
            q.push(max(y,a[i]));
            while(h1 <= 0 && !q.empty())
            {
                h1 += q.top();
                q.pop();
                cnt--;
            }
        }
        if(i == n+1)
        {
            printf("Lose\n%d\n",max_cnt*x);
        }
        else
        {
            printf("Win\n%d\n",i);
        }
    }
    return 0;
}

还有一道题,之后补充

你可能感兴趣的:(ACM,Problems)