A. Rectangle Cutting
显然,要至少存在一条边的长度为偶数,才可以切割成两个完全一样的部分。
并且切完之后不能是正方形。
直接模拟即可。
#include <iostream>
using namespace std;
bool solve(){
int a, b; cin >> a >> b;
if(a&1 && b&1) return false;
if(a & 1){
if(b/2 == a) return false;
return true;
}
if(b & 1){
if(a/2 == b) return false;
return true;
}
return true;
}
int main(){
int _; cin >> _; while(_--) cout << (solve() ? "YES" : "NO") << '\n';
return 0;
}
B. Equalize
双指针。因为要加的是一个 1 − n 1-n 1−n 的排列,所以开始相同的元素加完不可能相同,因此先去重。
可以证明,若区间 [ l , r ] [l, r] [l,r] 的极差 d < n d < n d<n,则必然可以加成相同的数。
排序之后找极差小于 n n n 的最长连续区间即可。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void solve(){
int n; cin >> n;
vector <int> a(n); for(auto &x : a) cin >> x;
sort(a.begin(), a.end()); int _n = unique(a.begin(), a.end()) - a.begin();
int ans = 0;
for(int l = 0, r = 0; l < _n; l++){
while(r+1 < _n && a[r+1] - a[l] < n) r++;
ans = max(ans, r - l + 1);
}
cout << ans << endl;
}
int main(){
int _; cin >> _; while(_--) solve();
return 0;
}
C - Physical Education Lesson
由题,
对于 k ∈ Z k \in \mathbb Z k∈Z,我们可以写出如下代码生成第 n n n 个数:
int calc(int n, int k){
n--, k--;
return ((n / k) % 2 == 0 ? 1 + (n%k) : k - (n%k) + 1);
}
因此,对于一组 ( n , k , x ) (n, k, x) (n,k,x),
一定有 x = 1 + ( ( n − 1 ) % ( k − 1 ) ) x = 1 + ((n-1) \% (k-1)) x=1+((n−1)%(k−1)) 或 x = ( k − 1 ) − ( ( n − 1 ) % k ) + 1 x = (k-1) - ((n-1) \% k) +1 x=(k−1)−((n−1)%k)+1 成立。
即: k ∣ ( n − 1 ) + x − 1 k | (n-1)+x-1 k∣(n−1)+x−1 或 k ∣ ( n − 1 ) − x + 1 k | (n-1)-x+1 k∣(n−1)−x+1。
所以枚举 ( n − 1 ) + ( x − 1 ) (n-1)+(x-1) (n−1)+(x−1) 和 ( n − 1 ) − ( x − 1 ) (n-1)-(x-1) (n−1)−(x−1) 的因子中符合条件的个数即为答案。
开个 set
记录即可。
#include <iostream>
#include <set>
#define int long long
using namespace std;
int n, x;
set <int> s;
bool check(int k){
return k > 0 && (((n / k) & 1) == 0 ? 1 + (n%k) : k - (n%k) + 1) == x;
}
void calc(int p){
for(int i = 1; i*i <= p; i++){
if(check(i)) s.insert(i);
if(check(p/i)) s.insert(p/i);
}
}
void solve(){
s.clear(); cin >> n >> x; n--;
calc(n+x-1);
calc(n-x+1);
cout << s.size() << '\n';
}
signed main(){
int _; cin >> _; while(_--) solve();
return 0;
}
D - Lonely Mountain Dungeons
答案是单峰的,可以用三分之类的做法来做。
但还有一种很优雅的根号做法:
参考题解:https://www.luogu.com.cn/blog/MaxBlaze/cf1928-ti-xie
由题 ∑ c i ≤ 2 × 1 0 5 \sum c_i \le 2 \times 10^5 ∑ci≤2×105,又有 1 ≤ c i ≤ 2 × 1 0 5 1 \le c_i \le 2 \times 10^5 1≤ci≤2×105,可知不同的 c i c_i ci 最多有 2 × 1 0 5 \sqrt{2 \times 10^5} 2×105 种,去重后暴力计算答案即可。
#include <iostream>
#include <vector>
#include <algorithm>
#define int long long
using namespace std;
inline int C(int t){ return (t * (t-1)) >> 1; }
int calc(int s, int t){
int ret = C(t - s % t) * (s / t) * (s / t)
+ C(s % t) * (s / t + 1) * (s / t + 1)
+ (t - s % t) * (s % t) * (s / t) * (s / t + 1);
return ret;
}
const int maxn = 2e5 + 5;
int c[maxn], cnt[maxn];
void solve(){
int n, b, x, sum = 0; cin >> n >> b >> x;
for(int i = 1; i <= n; i++) cin >> c[i], sum += c[i], cnt[c[i]]++;
sort(c+1, c+1+n); n = unique(c+1, c+1+n) - c - 1;
int ans = 0;
for(int i = 1; i <= sum; i++){
int tmp = 0;
for(int j = 1; j <= n; j++) tmp += cnt[c[j]] * calc(c[j], i) * b;
ans = max(ans, tmp - (i-1)*x);
}
for(int i = 1; i <= n; i++) cnt[c[i]] = 0;
cout << ans << '\n';
}
signed main(){
int _; cin >> _; while(_--) solve();
return 0;
}