A. Level Statistics
# 题目总链接
思路
- 题意:给我们n次按时间顺序排序的刷图情况,对于每次刷图情况有两个参数 a、b,a:到目前已经刷了多少次图,b为到目前已经成功刷了所少次图 (注意对于每次刷图a的次数要+1, 可以是成功的刷过去了那么b的数值也要+1,也可以是没有刷过去失败了),让我们判断这个n刷图情况是否符合逻辑
- 分析:水题一个,但是其中的逻辑还是要搞清楚的
- 刷图数量a不能递减,成功刷图数量b也不能递减,
- 成功刷图数量b<=刷图数a
- 成功刷图数量的增加量 <= 刷图数量的增加量
代码
#include<vector>
#include<iostream>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string>
#include<map>
#include<vector>
#include<queue>
using namespace std;
void fre() { freopen("A.txt","r",stdin); freopen("Ans.txt","w",stdout); }
#define ll long long
#define INF 0x3f3f3f3f
const int mxn = 3e5;
int ar[mxn], br[mxn];
int main()
{
/* fre(); */
int t;
scanf("%d", &t);
while(t --)
{
int n;
scanf("%d", &n);
int fg = 1;
for(int i = 1; i <= n; i ++)
{
scanf("%d %d", &ar[i], &br[i]);
if(br[i] > ar[i]) fg = 0; //成功刷图的次数 不可能大于 刷图的数量
if(i >= 2 && fg)
{
if(ar[i] < ar[i - 1] || br[i] < br[i - 1]) //刷图的次数和成功完成刷图的次数 都必须是非严格递增的
fg = 0;
else if(br[i] - br[i - 1] > ar[i] - ar[i - 1]) //刷图成功增加的次数 不肯多余 刷图的增加次数
fg = 0;
}
}
if(fg)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
B. Middle Class
思路
-
题意:跟我们n个手中的金钱数量 ,当一个人手中的钱 的时候被认为是富人,现在政府要增加有钱人的数量,通过选定一些人把它们手中的钱求和,然后在均分给他们,设此时它们手中的钱数为y,如果如果y>=x,那么这些人就都变成富人了,就是通过这个手段 最多可让多少人变成富人?
-
分析:让序列 按从大到小排序,求一下它们的前缀和sum[i],之后在维护一下 sum[i]/i 的最大值(这个维护的前提是sum[i]/i > x,注意转化为double云算的时候)
代码
#include<vector>
#include<iostream>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string>
#include<map>
#include<vector>
#include<queue>
using namespace std;
void fre() { freopen("A.txt","r",stdin); freopen("Ans.txt","w",stdout); }
#define ll long long
#define INF 0x3f3f3f3f
const int mxn = 3e5;
ll sum[mxn];
int main()
{
/* fre(); */
int t;
scanf("%d", &t);
while(t --)
{
ll n, x;
scanf("%lld %lld", &n, &x);
for(int i = 1; i <= n; i ++)
scanf("%lld", &sum[i]);
sort(sum + 1, sum + 1 + n, greater<int>());
int ans = 0;
for(int i = 1; i <= n; i ++)
{
sum[i] += sum[i - 1];
if(sum[i] >= i * x)
ans = max(ans, i);
}
printf("%d\n", ans);
}
return 0;
}
C. Circle of Monsters
思路
-
题意:n个怪兽顺时针站成一圈,每个怪兽又两个属性,生命值ai,爆炸伤害值bi,我们可以对怪兽进行攻击,每次攻击减少怪兽1生命值,当i怪兽被打死之后,它会爆炸,仅能使i+1位置的怪兽的生命值减少bi(当i==1时,第1只怪兽的生命值减少bn),当一个怪兽的生命值<=0 时被认为是死亡,问我们最少需要多少次攻击把所有的怪兽杀死?
-
分析:其实我们思考,所有怪兽总的生命值是一定的,要想减少攻击次数,那么就要充分利用它们的爆炸伤害,我们不妨假设它们都爆炸,之后看看剩余的统计一下还有那些怪兽还存活着,在统计一下爆炸后所有活着的怪兽的总的生命值sum,但是我们要想引发这些怪兽一个接一个的爆炸,那么就要先杀死一个怪兽,但是我们不知道杀死那一只最优,所以枚举讨论先杀那一只(我们设先杀死x、位置的那一只),既然先杀死x就不可能就不可能被前一只的怪兽的爆炸所伤,如果x的不能被前一只怪兽给炸死,那么之前我们统计的sum就要减去x被炸之后的生命,减完之后的sum,就是其他怪兽的还活着的总生命,这是可以认为它们已经不回在爆炸了,此时的sum值就是我们还要攻击的次数了
代码
#include<vector>
#include<iostream>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string>
#include<map>
#include<vector>
#include<queue>
using namespace std;
void fre() { freopen("A.txt","r",stdin); freopen("Ans.txt","w",stdout); }
#define ll long long
#define INF 0x3f3f3f3f
const int mxn = 4e5;
ll sum;
ll a[mxn], b[mxn];
ll c[mxn];
int main()
{
/* fre(); */
int t;
scanf("%d", &t);
while(t --)
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
{
scanf("%lld %lld", &a[i], &b[i]);
if(i >= 2)
c[i] = a[i] - b[i - 1];
}
c[1] = a[1] - b[n];
sum = 0;
for(int i = 1; i <= n; i ++)
{
if(c[i] > 0)
sum += c[i];
}
ll ans = 1e18;
for(int i = 1; i <= n; i ++)
{
if(c[i] > 0)
ans = min(ans, sum - c[i] + a[i]);
else
ans = min(ans, sum + a[i]);
}
printf("%lld\n", ans);
}
return 0;
}
D. Minimum Euler Cycle
思路
-
题意:给我们一个有n结点的完全有向图(定义:对于图中任意两个节点:u,v, 总存在两条有向边u–>v、v–>u),问我们将所有的路径都只走一遍,如何走出字典序最小的路径。
-
分析:画出n == 5 的欧拉环路径
[…] 可以认为是一个区间,对于每个区间中的规律是很好找的,现在我们做的就是输出[l, r] 区间的数字,我们可以用二分找出l所位于的[…]区间,之后在用for循从我们找到的这个区间[…]出开始遍历,当与[l, r]区间重叠的时候,就输出,,,,最后要特判输出最后一个区间的输出
代码
#include<vector>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string>
#include<map>
#include<vector>
#include<queue>
using namespace std;
void fre() { freopen("A.txt","r",stdin); freopen("Ans.txt","w",stdout); }
#define ll long long
#define INF 0x3f3f3f3f
const int mxn = 3e5;
ll sum[mxn];
ll n, l, r;
ll work(ll x)
{
if(x != n)
{
return x * ( 2*n - x - 1);
}
else
{
x --;
return x * ( 2*n - x - 1) + 1;
}
}
int main()
{
/* fre(); */
int t;
scanf("%d", &t);
while(t --)
{
scanf("%lld %lld %lld", &n, &l, &r);
ll L = 0, R = n;
ll p; //找位置
while(L <= R)
{
ll mid = (L + R) >> 1;
if(work(mid) >= l)
{
R = mid - 1;
p = mid;
}
else
{
L = mid + 1;
}
}
ll now = work(p - 1);
for(ll i = p; i < n; i ++)
{
for(ll j = i + 1; j <= n; j ++)
{
now ++;
if(now >= l && now <= r)
printf("%lld ", i);
now ++;
if(now >= l && now <= r)
printf("%lld ", j);
if(now > r)
break;
}
if(now > r)
break;
}
if(work(n) == r)
printf("1");
printf("\n");
}
return 0;
}