Codeforces Round 919 (Div. 2)
A-Satisfying Constraints
模拟
记录上下界,begin、end
如果发现有一次begin>end 直接输出0
或者 end<begin 也输出0
ans = end-begin+1
然后记录每一个不能等于的点到vector,然后遍历vector
如果存在一个点 x ∈ [ b e g i n , e n d ] x\in[begin,end] x∈[begin,end]
ans–
#include<bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
const int N = 1e6 + 7;
typedef long long ll;
int main() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
ll begin=0, end=1e9;
vector<ll> v;
bool is_yes = 1;
for (int i = 1; i <= n; i++) {
int a; ll x;
cin >> a >> x;
if (a == 1) {
if(x<=end)
begin = max(begin,x);
else{
is_yes=0;
}
}
else if (a == 2) {
if(x>=begin)
end = min(end,x);
else {
is_yes = 0;
}
}
else {
v.push_back(x);
}
}
if (is_yes == 0){
cout<<0<<endl;
continue;
}
ll ans = end - begin+1;
for (int i = 0; i < v.size(); i++) {
if (v[i] <= end and v[i] >= begin)ans--;
}
cout << ans << endl;
}
}
B-Summation Game
贪心,枚举
先将数组排序,然后枚举爱丽丝要消除的元素个数。
预处理出前缀和 sum
和后缀和 nxt[i]
如果爱丽丝要消除j个元素(必然从最大的开始消除),那么消除掉的元素之和:nxt[n-j]
然后鲍勃只需要从最大的开始,选x个,使其乘上-1
也就是减去 2倍的 nxt[n-j-x]-nxt[n-j]
注意到,如果不满x个,那么我们就选剩下的所有: sum-nxt[n-j]
答案就是 : sum - min( 2nxt[n-j-x]-nxt[n-j] )
只要枚举j 使2nxt[n-j-x]-nxt[n-j] 最小即可
(一开始wa了一发,后面都改成longlong就过了,不开longlong见祖宗啊)
#include<bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
const int N = 1e9 + 7;
typedef long long ll;
int main() {
int t;
cin >> t;
while (t--) {
int n, k, x;
cin>>n>>k>>x;
vector<ll> a;
vector<ll> nxt(n + 2);
ll sum = 0;//前缀和
for (int i = 0; i < n; i++) {
int temp;
cin >> temp;
sum += temp;
a.push_back(temp);
}
sort(a.begin(), a.end());//排序
for (int i = a.size()-1; i >= 0; i--) {//后缀和
nxt[i] = nxt[i + 1] + a[i];
}
ll ans = 0,bns=0;
ll cnt=N;
for (int i = 0; i <= k; i++) {//枚举k
if (n - i >= 0) {
ans= nxt[n-i]; //移掉的
if(n-i-x>=0){
bns=nxt[n-i-x]-nxt[n-i];//如果移去之后,还有大于等于x个元素,记录最后x个元素
}
else{ //不足x个元素
bns=sum-nxt[n-i]; //剩下的元素就是总和-移去的元素
}
cnt=min(cnt,2*bns+ans);
}
}
cout << sum-cnt << endl;
}
}
C-Partitioning the Array
数学、gcd、枚举
第一:
题目要我们将 a i . . . a n a_i...a_n ai...an划分为为k段。
那么说明 k 是 n的因数
第二:
我们需要找到m,使得每一段的数,分别对m取模的结果是一 一对应的
也就是
(ps:$ \equiv$ 是模意义下的等号,表示左右两边模以m相等,也就是同余)
- a 1 ≡ a 1 + k ( m o d m ) a_1\equiv\ a_{1+k}(mod\ m) a1≡ a1+k(mod m)
- a 2 ≡ a 2 + k ( m o d m ) a_2\equiv\ a_{2+k}(mod\ m) a2≡ a2+k(mod m)
- a 3 ≡ a 3 + k ( m o d m ) a_3\equiv\ a_{3+k}(mod\ m) a3≡ a3+k(mod m)
- …
- a 1 + k ≡ a 1 + k + k ( m o d m ) a_{1+k}\equiv\ a_{1+k+k}(mod\ m) a1+k≡ a1+k+k(mod m)
- a 2 + k ≡ a 2 + k + k ( m o d m ) a_{2+k}\equiv\ a_{2+k+k}(mod\ m) a2+k≡ a2+k+k(mod m)
- …
- a n − k ≡ a n ( m o d m ) a_{n-k}\equiv\ a_{n}(mod\ m) an−k≡ an(mod m)
而对于任意的: a i ≡ a i + k ( m o d m ) a_i\equiv\ a_{i+k}(mod\ m) ai≡ ai+k(mod m)
等价于: ∣ a 1 − a 1 + k ∣ ≡ 0 ( m o d m ) |a_1-a_{1+k}|\equiv\ 0 (mod\ m) ∣a1−a1+k∣≡ 0(mod m)
(这个转换很常用)
等价于:m是 ∣ a 1 − a 1 + k ∣ |a_1-a_{1+k}| ∣a1−a1+k∣的一个因子
显然,要找到一个m,使之满足上面的所有式子,那么m必然是它们的最大公约数。
$ gcd(|a_{1+k}-a_1|,|a_{2+k}-a_2|…,|a_{n}-a_{n-k}||)$
求多个数的最大公约数,只需要两两求即可,因为最大公约数满足结合律。
#include<bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
const int N = 1e6 + 7;
typedef long long ll;
int __gcd(int a, int b) {
return b ? __gcd(b, a % b) : a ;
}
int main() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> v;
for (int i = 1; i <= n; i++) {
int temp;
cin >> temp;
v.push_back(temp);
}
ll ans = 0;
for (int i = 1; i <= n; i++) {
if (n % i == 0) {
int g = 0;
for (int j = 0; j < n - i; j++) {
g = __gcd(g, abs(v[j+i]-v[j]));
}
if (g != 1)ans++; //当g==0时,说明,v[j+1]=v[j],也就是每一项都相同
}
}
cout << ans << endl;
}
}
0;
for (int j = 0; j < n - i; j++) {
g = __gcd(g, abs(v[j+i]-v[j]));
}
if (g != 1)ans++; //当g==0时,说明,v[j+1]=v[j],也就是每一项都相同
}
}
cout << ans << endl;
}
}