Educational Codeforces Round 85 [Rated for Div. 2]
A. Level Statistics
给出n组(pi,ci),每轮可以选择给p和c同时+1,或者只给p 进行+1,两组数据之间可以进行多轮,判断给定序列是否合法。
Solution
判断不合法的情况:
1.pi < ci
2.pi < pi-1 || ci < ci-1
3.pi - pi-1 < ci - ci-1
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int SZ = 200 + 20;
int c[SZ],p[SZ];
bool flag;
int main()
{
int T;
scanf("%d",&T);
while(T -- )
{
int n;
scanf("%d",&n);
flag = 0;
for(int i = 1;i <= n;i ++)
{
scanf("%d%d",&p[i],&c[i]);
if(p[i] < c[i])
{
flag = 1;
}
}
if(flag == 1)
{
printf("NO\n");
continue;
}
for(int i = 2;i <= n;i ++ )
{
if(p[i] < p[i - 1] || c[i] < c[i - 1])
{
flag = 1;
break;
}
if(p[i] - p[i - 1] < c[i] - c[i - 1])
{
flag = 1;
break;
}
}
if(flag == 1) printf("NO\n");
else printf("YES\n");
}
return 0;
}
B. Middle Class
给出n个数字,和一个基准x。每次可选择n个数字中的任意个,然后把他们均匀分配,即把他们加起来再均分给这几个位置。为经过任意次操作后,大于等于基准x的数字的最大个数。
Solution
贪心的选大的,总比选小的优。
先排一下序,从最大的开始,然后依次加次大,第三大,看看当前和是否均分还能超过x,如果当前这个加上不能均分大于等于x。那么这个不加 ,并停止。选择的总个数就是答案。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int SZ = 1e5 + 20;
ll num[SZ];
int main()
{
int T;
scanf("%d",&T);
while(T -- )
{
ll n,k;
ll sum = 0;
ll ans = 0;
scanf("%lld%lld",&n,&k);
for(int i = 1;i <= n;i ++ )
{
scanf("%lld",&num[i]);
}
sort(num + 1,num + n + 1);
for(int i = n;i >= 1;i -- )
{
if((num[i] + sum) / (n - i + 1) >= k)
{
sum += num[i];
ans ++;
}
else break;
}
printf("%lld\n",ans);
}
return 0;
}
C. Circle of Monsters
给一个怪兽围成的圈,每次可以选择对一个怪兽造成1点伤害,每个怪兽有ai点生命值,如果它被击杀,那么他会爆炸对下一个怪兽造成bi点伤害,如果下一个怪兽被bi点伤害杀死,它也会爆炸下去,依次类推,如果它的下一个怪兽已经死了,那爆炸不会传递下去。问最少用多少枪可以让所有怪兽爆炸。
Solution
让爆炸伤害最大化,则用枪的次数最少。最大化爆炸伤害,就是一次爆炸就可以引发全部的爆炸。
处理方法就是先把每个怪兽的血量打到小于等于上一个怪兽的bi。这样就能保证炸一个全炸,然后在选择一个当前血量最低的打爆。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int SZ = 3e5 + 10;
struct zt
{
ll a,b;
}node[SZ];
int main()
{
int T;
scanf("%d",&T);
while(T -- )
{
int n;
ll ans = 0;
ll minn;
scanf("%d",&n);
for(int i = 1;i <= n;i ++ )
scanf("%lld%lld",&node[i].a,&node[i].b);
if(node[1].a > node[n].b)
{
ans += (node[1].a - node[n].b);
node[1].a = node[n].b;
}
minn = node[1].a;
for(int i = 2;i <= n;i ++ )
{
if(node[i].a > node[i - 1].b)
{
ans += node[i].a - node[i - 1].b;
node[i].a = node[i - 1].b;
}
minn = min(minn,node[i].a);
}
printf("%lld\n",ans+ minn);
}
return 0;
}
D. Minimum Euler Cycle
给一个完全图,把每条边走一遍,a-b ,b-a算两条边,点可以走无限次,输出字典序最小的欧拉回路的l到r段。
Solution
可以看出
1213141516…1n
2324252627…2n
3435363738…3n
…
1
这样可以保证字典序最小
并且每一组的个数是2*(n - 1)个共n - 1组, 最后还有一个单独的1。
我们只要找到l和r所在的分组,然后找规律输出即可。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
ll n,l,r;
int main()
{
int T;
scanf("%d",&T);
while(T -- )
{
scanf("%lld%lld%lld",&n,&l,&r);
ll i,j; //i为l的分组 j为r的分组
for(i = 1;i <= n - 1;i ++ )
{
if(l > 2 * (n - i)) l -= 2 * (n - i);
else break;
}
for(j = 1;j <= n - 1;j ++ )
{
if(r > 2 * (n - j)) r -= 2 * (n - j);
else break;
}
//如果在同一组 只输出本区间的l到r 特殊处理最后一个单独的1
if(i == j)
{
if(j == n) printf("1");
else
for(ll p = l;p <= r;p ++ )
{
if(p % 2 == 1) printf("%lld ",i);
else printf("%lld ",i + p/2);
}
}
else //l和r在不同分组,单独处理l所在分组 r所在分组 和中间的组
{
for(ll p = l;p <= 2 * (n - i);p ++ )
{
if(p % 2 == 1) printf("%lld ",i);
else printf("%lld ",i + p/2);
}
for(ll p = i + 1;p <= j - 1;p ++ )
{
for(ll q = 1;q <= 2 * (n - p);q ++ )
if(q % 2 == 1) printf("%lld ",p);
else printf("%lld ",p + q/2);
}
if(j == n) printf("1");//单独处理最后一个1
else
for(ll p = 1;p <= r;p ++ )
{
if(p % 2 == 1) printf("%lld ",j);
else printf("%lld ",j + p/2);
}
}
printf("\n");
}
return 0;
}
2020.4.13