2014 上海区域赛I,J ,B

省赛组队磨合,呜呜呜呜爆零,气哭

这也是第一次打组队赛,深深的感觉到了这个世界对咸鱼队的伤害,希望和卢聚聚,和帅帅的学长一起变强

当时也就做了J题做了好久一直wa,就鸽鸽了。。


  J题感觉是个智商题,要把求的那个人单独拿出来进行讨论即可

(千万不要忘记了判断奇偶)如果是奇数那么最后一场 求最大未晋级的时候只能输或者平局 而最小晋级 只能赢或者平

  详情都在代码上写着

 

#include <iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
int main()
{
    int T;
    scanf("%d",&T);
    int  tt=0;
    while(T--)
    {
        ll n,m;
        scanf("%lld%lld",&n,&m);
        ll a,b,c;
        scanf("%lld%lld%lld",&a,&b,&c);
        if(a<c) swap(a,c);
        /*
           将人数分为 m 1 n-m-1
           算最大的未晋级人的分数 (即就是中间1的分值最大即可)
           1.  首先这个人要全赢或者全平后面的所有人(如果输一场的话,他输的那个人有可能全赢,那么就破坏了游戏规则)
           2.  其次和后面的人输赢对半,或者全平
           3.  如果m是奇数的话那他最后一场必须输或者平局
        */
        ll temp1,temp2,ans1,ans2;
        ans1=(n-m-1)*max(b,a);
        temp1=m/2*(a+c);
        temp2=m/2*(2*b);
        ans1+=max(temp1,temp2);
        if(m%2) ans1+=max(b,c);

        /*
          将人数分为 m-1 1 n-m
          算最小的晋级人的分数(同上,只不过算最小的而已)
          1.首先这个人要全输或者全平前面的m-1个人
          2.其次要输赢对半,或者全平后面的人
          3.如果n-m是奇数的话那么最后一场要么赢要么平
        */
        ans2=min(b,c)*(m-1);
        temp1=(n-m)/2*(a+c);
        temp2=(n-m)/2*(2*b);
        ans2+=min(temp1,temp2);
        if((n-m)%2) ans2+=min(a,b);

        printf("Case #%d: %lld %lld\n",++tt,ans1,ans2);
    }
    return 0;
}

I 就是对stl 中multiset 的应用然鹅萌新并没有用过于是,鸽鸽

题意就是:两个人都有一堆小兵,每个小兵有攻击防御,然后我们要用我们的小兵去消灭他们的小兵,问做多能剩下几个小兵,如果不能打过输出(-1)(当一个小兵的攻击大于等于另一个小兵的防御,那么另一个小兵就会死)注意这里面的攻击是敌我同时攻击彼此

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+100;
struct node
{
    ll pow;
    ll def;
}our[maxn],enm[maxn];
//pow 伤害 def 防御
bool cmp1(const struct node a,const struct node b)
{
    if(a.pow!=b.pow) return a.pow > b.pow;
    return a.def>b.def;
}
//对我们自己排序,第一权值为攻击从高到低,第二个防御从高到低
bool cmp2(const struct node a,const struct node b)
{
    if(a.def!=b.def) return a.def > b.def;
    return a.pow>b.pow;
}
//对敌人排序,第一权值为防御从高到第,第二个是攻击从高到低
int main()
{
    int T;
    scanf("%d",&T);
    int tt=0;
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);

        multiset <int> myset; //第一次用,set默认从小到大排序
        myset.clear();

        for(int i=0;i<n;i++)
        {
          scanf("%I64d %I64d",&our[i].pow,&our[i].def);
        }
        for(int i=0;i<m;i++)
        {
          scanf("%I64d %I64d",&enm[i].pow,&enm[i].def);
        }
        if(n<m)
        {
            //如果人数不足直接可以输出-1 continue
            printf("Case #%d: %d\n",++tt,-1);
            continue;
        }
        bool flag=1;//标记是否成功
        int now=0,ans=0;//now是当前要判断我们troop的下标,ans是我们死的人数

        sort(our,our+n,cmp1);//按攻击排序
        sort(enm,enm+m,cmp2);//按防御排序

        for(int i=0;i<m;i++)
        {
            //遍历敌人
            for(int j=now;j<n;j++)
            {
                if(our[j].pow>=enm[i].def)
                {
                    //如果当前我们的troop的攻击大于等于敌人的防御扔到multiset中
                    //我们的下标向后移
                    myset.insert(our[j].def);
                    now++;
                }
                else break;
            }

            if(myset.empty())
            {
                //如果当前set中没有节点说明当前我们不能消灭这个敌人
                flag=0; break;
            }

            else
            {
                //能不损失军队,则用我方生命值恰好高于敌方的去消灭
                //倘若必须损失军队,则损失当前生命值最低的
                multiset<int>::iterator it;
                it=myset.upper_bound(enm[i].pow);
                if(it!=myset.end())
                {
                    myset.erase(it);
                }
                else
                {
                    myset.erase(myset.begin());
                    ans++;
                }
            }
        }
       if(flag) printf("Case #%d: %d\n",++tt,n-ans);
       else printf("Case #%d: %d\n",++tt,-1);
    }
    return 0;
}



B:题意不详,,,嘿嘿,反正自己没读懂,是看了别人的博客搞了个似懂非懂的。反正先记下来把

就是一个车在网格里面跑,每个网格都站这一个人(每个人都一直正面盯这小车)

问每个人旋转次数的平方(正向旋转减逆向的平方和)

二维前缀和问题,然鹅并不会。


#include<bits/stdc++.h>
using namespace std;
/*
维护二维前缀和;
为了记录每个点的转身次数,
由大佬结论得:对于一个方格中的人来说,如果要有一个完整的时针旋转,则必然是一边走下去,一边走上去,且”包含”所以不用考虑R,L.
若车在人的正左方下降了X次,上升了Y次,那么那个人的旋转圈数便是abs(X-Y)。
然后暴力模拟车的移动
*/
vector< vector<int> > v;
void add(int x1,int x2,int y ,int w)
{
    v[x1][y]+=w;
    v[x2][y]-=w;
}
int main()
{
    int T,tt=0;
    scanf("%d",&T);
    while(T--)
    {
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        v=vector< vector <int> >(n+10,vector<int> (m+10,0));
        //这个确实没看懂 ,悲剧辣么大(原来没有用过)
        int x=1,y=1;
        while(k--)
        {
            char s[5];
            int len;
            scanf("%s%d",s,&len);
            if(s[0]=='L') y-=len;
            else if(s[0]=='R') y+=len;
            else if(s[0]=='U')
            {
                add(x-len,x,y,1);
                x-=len;
            }
            else
            {
                add(x,x+len,y,-1);
                x+=len;
            }
        }
        long long ans=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                v[i][j]+=(v[i-1][j]-v[i-1][j-1])+v[i][j-1];
                /*
                    顺序处理那么前面的前缀和肯定一定处理过了
                    那么v[i-1][j]-v[i-1][j-1] 就是影响这个点左侧的上下次数,就是他行的前缀和
                    同时加上他前一个点已经维护的前缀和v[i][j-1],就是它列的前缀和
                    行和列街上本身就是该点的上下次数
                     !!!这个地方有点染要多看看!!!
                */
                ans+=v[i][j]*v[i][j];
            }
        }
        printf("Case #%d: %lld\n",++tt,ans);
    }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值