省赛组队磨合,呜呜呜呜爆零,气哭
这也是第一次打组队赛,深深的感觉到了这个世界对咸鱼队的伤害,希望和卢聚聚,和帅帅的学长一起变强
当时也就做了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;
}