C. Circle of Monsters
题意:
首先我们要想, 如何用最少的子弹造成最大的伤害, 即尽可能的利用爆炸伤害, 所以从某个怪物开始, 每次射击的都是它后面未被炸死的怪物, 所以问题就变成了,从哪一个怪物开始射击, 所以我们枚举从每一个怪物开始,最开始我们要预处理出来利用上一个怪物的爆炸伤害, 我们还需要补几枪
#include<bits/stdc++.h>
#define x first
#define int long long
#define ll long long
#define y second
#define gg exit(0);
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define db printf("debug\n");
const int N = 5e5 + 10;
using namespace std;
typedef pair<ll, ll>PII;
int T;
long long a[N], b[N], n, c[N];
void solve()
{
cin >> n;
for(int i = 1; i <= n; i ++ ) cin >> a[i] >> b[i];
long long sum = 0;
for(int i = 1; i <= n; i ++ )
{
if(i == 1) c[i] = max((ll)0, a[i] - b[n]);
else c[i] = max((long long )0, a[i] - b[i - 1]);
sum += c[i];
}
long long ans = 1e18;
for(int i = 1; i <= n; i ++ )
ans = min(ans, sum - c[i] + a[i]); //因为从这个怪物开始, 所以这个怪物受到的爆炸伤害不能计算在内
cout << ans << '\n';
}
signed main()
{
io;
//T = 1;
cin >> T;
while(T -- )
solve();
}
C. Ilya and Sticks
首先要面积最大,我们肯定会先用长的木棍拼在一起, 所以从大到小排序肯定没问题, 然后每四个一处理, 但是这里就出了点问题, 不一定是每四个一处理, 只要相邻两个能通过工具凑成一对, 就可以与其他对凑成矩形, 所以我们排序后,要每两个一处理, 然后放入数组, 最后一起计算面积
#include<bits/stdc++.h>
#define x first
#define ll long long
#define y second
#define gg exit(0);
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define db printf("debug\n");
const int N = 5e5 + 10;
using namespace std;
typedef pair<ll, ll>PII;
int T;
ll n, a[N];
bool cmp(int a, int b)
{
return a > b;
}
void solve()
{
cin >> n;
vector<ll>b;
for(int i = 1; i <= n; i ++ )
cin >> a[i];
sort(a + 1, a + 1 + n, cmp);
ll s = 0;
for(int i = 1; i <= n - 1; i ++)
if(abs(a[i] - a[i + 1]) <= 1 ) //符合条件
b.push_back(a[i + 1]), i ++; //放入数组
for(int i = 0; i < (int)b.size() - 1; i += 2 ) //计算面积
s += b[i] * b[i + 1];
cout << s << '\n';
}
signed main()
{
io;
T = 1;
// cin >> T;
while(T -- )
solve();
}
C. New Year Book Reading
题意:
首先我们要确定每本书的初始位置, 我们不难知道, 通过一定的操作之后, 不论你书怎么放, 他的位置一定是固定的, 因为每次我们都要把那本书放到顶部, 所以当每本书都被放到顶部后, 他的位置就已经固定了, 与初始位置无关, 但是在每本书第一次本拿时, 与初始位置有关, 所以我们要根据每本书第一次本拿的位置, 确定每本书的初始位置
确定完初始位置后, 然后模拟即可
#include<bits/stdc++.h>
#define x first
#define ll long long
#define y second
#define gg exit(0);
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define db printf("debug\n");
const int N = 5e5 + 10;
using namespace std;
typedef pair<ll, ll>PII;
int T;
ll n, w[N], b[N], m;
stack<int>s;
vector<int>a, c;
bool st[N];
void solve()
{
cin >> n >> m;
for(int i = 1; i <= n; i ++ ) cin >> w[i];
for(int i = 1; i <= m; i ++ ) cin >> b[i];
for(int i = 1; i <= m; i ++ )
if(!st[b[i]]) //这本书第一次出现
{
a.push_back(b[i]);
st[b[i]] = true;
}
for(int i = (int)a.size() - 1; i >= 0; i -- ) s.push(a[i]); //初始位置
int sum = 0;
for(int i = 1; i <= m; i ++ )
{
while(s.top() != b[i]) //将需要看的书的上面的书,全部取出, 并放入c数组,以便于后面再放回
{
sum += w[s.top()]; //计算答案
c.push_back(s.top());
s.pop();
}
s.pop();
for(int i = (int)c.size() - 1; i >= 0; i -- ) s.push(c[i]);
s.push(b[i]); //别忘记把要看的这本书放在顶部
c.clear(); //清空
}
cout << sum << '\n';
}
signed main()
{
io;
T = 1;
// cin >> T;
while(T -- )
solve();
}
C. New Year and Rating
首先我们要确定初始分数, 只要确定了初始分数, 对于最终分数模拟即可求出, 但是如何确定最大的初始分数呢? 首先我们可以用两个变量表示初始分数的上下界, 如果下界大于上界就无解, 如果上界为正无穷, 说明最高分无上限, 然后通过每一次比赛, 可以确定上下界, 如果我下一场参加的是 B B B 组的比赛, 说明我这场比赛打完后我的得分的下界一定是小于等于1899的, 所以我们可以得到 r + c [ i ] < = 1899 r + c[i] <= 1899 r+c[i]<=1899 , 如果下一场参加的是 A A A 组的比赛, 那么我们打完这场比赛后一定是大于 1900 1900 1900 的, l + c [ i ] > = 1900 l + c[i] >= 1900 l+c[i]>=1900,这样我们就可以通过每一场比赛确定上下界了, 还要注意, 当第一场是A组比赛时, 我们需要把下界赋值为 1900 1900 1900, 否则赋值上界为 1899 1899 1899
#include<bits/stdc++.h>
#define x first
#define ll long long
#define y second
#define gg exit(0);
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define db printf("debug\n");
const int N = 5e5 + 10;
using namespace std;
typedef pair<ll, ll>PII;
int T;
int n, c[N], d[N];
void solve()
{
cin >> n;
for(int i = 1; i <= n; i ++ ) cin >> c[i], c[i] += c[i - 1], cin >> d[i];
int l = -1e9, r = 1e9;
if(d[1] == 1)
l = 1900;
else
r = 1899;
for(int i = 1; i < n; i ++ )
if(d[i + 1] == 1)
l = max(l, 1900 - c[i]); //更新下界
else r = min(r, 1899 - c[i]); //更新上界
if(l > r) cout << "Impossible\n";
else if(r == 1e9 ) cout << "Infinity\n";
else cout << r + c[n] << '\n';
}
signed main()
{
io;
T = 1;
// cin >> T;
while(T -- )
solve();
}
C. Anton and Fairy Tale
分析: 如果
n
<
=
m
n <= m
n<=m, 那么当
i
=
n
i = n
i=n 时, 谷仓就变空了, 如果当
n
>
m
n > m
n>m时, 在
1
1
1 ~
m
m
m, 谷仓的谷子是不会变的, 然后从第
m
+
1
m + 1
m+1 天开始, 谷仓的谷子每天减少1,2,3,4,5…,
所以我们可以推出 n - m <= (1 + x) * x / 2, 这里
n
−
m
n - m
n−m 是因为每天麻雀吃的是
m
+
x
m + x
m+x, (这里
m
+
x
m + x
m+x 是指的第
m
+
x
m + x
m+x 天, 所以我们二分找到答案即可)
#include<bits/stdc++.h>
#define x first
#define int long long
#define y second
#define gg exit(0);
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define db printf("debug\n");
const int N = 5e5 + 10;
using namespace std;
int T;
int n, m;
void solve()
{
cin >> n >> m;
if(n <= m)
cout << n << '\n';
else
{
int l = 0, r = 2e9; //左右边界
while(l < r) //二分
{
int mid = (l + r) / 2;
if((mid * (mid + 1)) / 2 >= (n - m)) r = mid;
else l = mid + 1;
}
cout << l + m << '\n';
}
}
signed main()
{
io;
T = 1;
// cin >> T;
while(T -- )
solve();
}
C. New Year and Permutation
对于这题,
n
n
n 很大, 所以我们要计算贡献, 首先我们需要找到合法区间的数量,设合法区间的长度为
l
e
n
len
len, 那么从
1
1
1 ~
n
−
l
e
n
+
1
n-len +1
n−len+1, 一共有
n
−
l
e
n
+
1
n - len + 1
n−len+1 个, 然后内部顺序有
!
l
e
n
!len
!len 种, 外部有
!
(
n
−
l
e
n
)
!(n - len)
!(n−len) 种, 所以我们枚举长度, 答案就出来了
a
n
s
=
∑
i
=
1
n
(
n
−
i
+
1
)
×
!
i
×
!
(
n
−
i
)
ans = \sum_{i=1}^n(n - i + 1) × ! i × !(n - i)
ans=i=1∑n(n−i+1)×!i×!(n−i)
#include<bits/stdc++.h>
#define x first
#define int long long
#define y second
#define gg exit(0);
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define db printf("debug\n");
const int N = 5e5 + 10;
using namespace std;
int T;
int n, m;
int fac[N];
void solve()
{
cin >> n >> m;
fac[0] = 1;
fac[1] = 1;
for(int i = 2; i <= n; i ++ ) fac[i] = fac[i - 1] * i % m; //预处理阶乘
int res = 0;
for(int i = 1; i <= n; i ++ ) //一定要记得多取模, 不然爆longlong了
res = ((res + ((((n - i + 1) * (n - i + 1) % m) * fac[i] % m )* fac[n - i]) % m ) % m);
cout << res % m << '\n';
}
signed main()
{
io;
T = 1;
// cin >> T;
while(T -- )
solve();
}
D. Vupsen, Pupsen and 0
分析: 当 n n n 为偶数时, 两两配对即可, 例如 一个数为 a a a, 另一个数为 b b b, 则 b b b 数组为 − b -b −b, a a a, 当 n n n 为奇数时, 我们只要处理掉前 3 3 3 个数, 剩下的就和偶数的情况一样了, 我们可以把三个数中的两个数看作一个整体, 然后当做两个数处理, 前提是这两个数的和不为 0 0 0, 例如,这三个数分别为 a , b , c a, b, c a,b,c, 我们可以是 a + b , c a + b, c a+b,c, 或者 a + c , b a + c, b a+c,b, 或者是 b + c , a b + c, a b+c,a, 其对应的 b b b 数组是 − c , − c , a + b -c, -c, a + b −c,−c,a+b, 或者 − b , − b , a + c -b, -b, a + c −b,−b,a+c, 或者是 − a , − a , b + c -a, -a, b + c −a,−a,b+c, 这三种情况并不是全都存在的, 要判断是否为 0 0 0,
#include<bits/stdc++.h>
#define x first
#define int long long
#define y second
#define gg exit(0);
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define db printf("debug\n");
const int N = 5e5 + 10;
using namespace std;
int T;
int n, m;
int a[N], b[N];
void solve()
{
cin >> n;
for(int i = 1; i <= n; i ++ ) cin >> a[i];
if(!(n & 1)) //偶数情况
{
for(int i = 1; i <= n; i ++ )
{
if(i % 2) cout << -1 * a[i + 1] << " ";
else cout << a[i - 1] << " ";
}
}
else
{
int x = a[1], y = a[2], z = a[3]; //处理前三个数
if(x + z != 0)
cout << -1 * y << " " << x + z << " " << -1 * y << ' ';
else if(x + y != 0)
cout << -1 * z << " " << -1 * z << " " << x + y << ' ';
else cout << y + z << " " << -1 * x << " " << -1 * x << ' ';
for(int i = 4; i <= n; i ++ )
{
if(!(i % 2)) cout << -1 * a[i + 1] << " ";
else cout << a[i - 1] << " ";
}
}
cout << '\n';
}
signed main()
{
io;
// T = 1;
cin >> T;
while(T -- )
solve();
}