头一次比赛的时候能做出6个题,最后没时间了不然就能ak了...不过这次确实简单...希望ak早日到来吧
A. Favorite Sequence
大意:
给出一个数组,要求依次输出第一个、倒数第一个、第二个、倒数第二个.....
思路:
模拟即可
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
int n, t,a[N];
int main(){
cin>>t;
while(t--){
cin >> n;
for (int i = 0; i < n;i++){
cin >> a[i];
}
for (int i = 0; i < n;i++){
if(i%2==0){
cout << a[i/2]<<' ';
}
else{
cout << a[n - i/2-1]<<' ';
}
}
cout << endl;
}
return 0;
}
B. Last Year's Substring
大意:
给出一个数字组成的字符串,问能否删掉一个连续的区间,使得最后字符串变为“2020”
思路:
直接判断2020是否在首尾两端或者是一部分在开头一部分在结尾即可
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
int t, n;
int main(){
cin >> t;
while(t--){
cin >> n;
string s;
cin >> s;
if (s.length() < 4) cout << "NO" << endl;
else if(s.substr(0,4)=="2020"||s.substr(n-4,n)=="2020")
cout << "YES" << endl;
else if((s.substr(0,1)=="2"&&s.substr(n-3,n)=="020")||(s.substr(0,3)=="202"&&s.substr(n-1,n)=="0"))
cout << "YES" << endl;
else if((s.substr(0,2)=="20"&&s.substr(n-2,n)=="20"))
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}
C. Unique Number
大意:
给出一个数x((1<=x<=50)),问能否找到一个数,这个数的每一位都不相同,且每一位加起来的和等于x,如果有多个,输出最小的那个
思路:
直接打表判断即可
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
int t, n;
int main() {
/*
for (int i = 1; i <= 50; i++) {
int can = 0;
for (LL j = 1; j <= 999999999 && can == 0; j++) {
LL temp = j;
int cnt[20];
int sum = 0;
memset(cnt, 0, sizeof cnt);
while (temp) {
int tt = temp % 10;
cnt[tt]++;
temp /= 10;
sum += tt;
}
int flag = 0;
for (int k = 0; k <= 9; k++) {
if (cnt[k] > 1) {
flag = 1;
break;
}
}
if (flag) {
continue;
}
if (sum == i) {
can = 1;
cout << j << ',' ;
}
}
}*/
LL res[50] = {1, 2, 3, 4, 5, 6,
7, 8, 9, 19, 29, 39,
49, 59, 69, 79, 89, 189,
289, 389, 489, 589, 689, 789,
1789, 2789, 3789, 4789, 5789, 6789,
16789, 26789, 36789, 46789, 56789, 156789,
256789, 356789, 456789, 1456789, 2456789, 3456789,
13456789, 23456789, 123456789, -1, -1, -1,
-1, -1};
cin>>t;
while(t--){
cin >> n;
cout << res[n - 1] << endl;
}
return 0;
}
D. Add to Neighbour and Remove
大意:
给出一个数组,每次操作可以选择一个数,将其加入左边或者右边的数,然后删掉这个数,问经过多少次操作可以将数组变为全部元素相等的数组。
思路:
可以想到最后的状态必然是多个区间和相等,那么直接先对原始的数组求和,然后求这个和的约数,枚举每个约数,看能否将数组划分为多个等于这个约数的区间即可
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int const N = 3e5 + 10;
int a[N];
LL sum[N];
vector<LL> yuenum;
int quchong[233];
// 试除法求约数
vector<LL> get_divisors(LL x) {
vector<LL> res; // 记录答案
for (int i = 1; i <= x / i; ++i) { // 枚举到sqrtx(x)
if (x % i == 0) { // 如果能够整除
res.push_back(i); // 放入i
if (i != x / i) res.push_back(x / i); // x/i不等于i,也放入答案中
}
}
sort(res.begin(), res.end()); // 排序
return res;
}
int t, n;
int main() {
cin >> t;
while (t--) {
cin >> n;
LL temp = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
sum[i] = sum[i - 1] + a[i];
temp += a[i];
}
yuenum = get_divisors(temp);
LL res = 0x3f3f3f3f;
for (int k = 0; k < yuenum.size(); k++) {
LL pre = 0;
int f = 1;
for (int i = 1; i <= n; i++) {
pre += a[i];
if (pre == yuenum[k]) {
pre = 0;
}
if (pre > yuenum[k]) {
f = 0;
break;
}
}
if (f!=0) res = min(res, n-temp/yuenum[k]);
}
cout<<res<<endl;
}
return 0;
}
E1. Close Tuples (easy version)
大意:
建议先看E2
相比于E2,只是限定了m=3,k=2,而且不取模。
思路:
做完E2之后直接把m=3 k=2改了交了,结果wa了...仔细想想发现不需要这么麻烦,因为m很小,直接手动算组合数即可
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL const N = 3e5 + 10, mod = 1e18;
int t, n, m, k;
int a[N];
int main() {
cin >> t;
while (t--) {
cin >> n;
m = 3;
k = 2;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
LL res = 0;
sort(a, a + n);
for (int i = 0; i < n; i++) {
int pos = upper_bound(a, a + n, a[i]+k) - a - 1;
if (pos - i + 1 < m) continue;
res += ((LL)pos - (LL)i )*((LL)pos - (LL)i -1)/2;
}
cout << res << endl;
}
return 0;
}
E2. Close Tuples (hard version)
大意:
给出n个数,以及m和k,问能找出多少组数,满足:每组里面有m个数,且这组数里面的最大值与最小值之差不大于k
思路:
先将数组排一下序,然后对于每个数,都upper_bound找一下比这个数大k的最大的数的下标pos,如果下标的差大于等于m,则答案+=(C_{m-1}^{pos-i})即可,代表以这个数为最小值有多少种取法。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int const N = 3e5 + 10, mod = 1e9 + 7;
int fact[N], infact[N];
LL qmi(LL a, LL k, LL p) {
LL res = 1;
while (k) {
if (k & 1) res = res * a % p;
k >>= 1;
a = a * a % p;
}
return res;
}
// 预处理
void init() {
fact[0] = infact[0] = 1;
for (int i = 1; i < N; ++i) {
fact[i] = (LL)fact[i - 1] * i % mod;
infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
}
}
int t, n, m, k, a[N];
int main() {
init();
cin >> t;
while (t--) {
cin >> n >> m >> k;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
LL res = 0;
sort(a, a + n);
for (int i = 0; i < n; i++) {
int pos = upper_bound(a, a + n, a[i]+k) - a - 1;
if (pos - i + 1 < m) continue;
//cout << "yes" << endl;
res += (LL)fact[pos - i ] * infact[m-1] % mod *
infact[pos - i + 1 - m] % mod;
res = res % mod;
}
cout << res << endl;
}
return 0;
}
F. The Treasure of The Segments
大意:
给出n个区间,问最少需要删去多少个区间,使得剩下的区间满足至少有一个区间和其他所有剩下的区间都相交
思路:
一开始想枚举每个区间然后算有哪些区间和它相交,写了一发发现不对,没有考虑被它包含的情况,后来发现只需要直接求和它不相交的区间有多少即可。
和区间i不相交的区间j满足:
j的右区间小于i的左区间 或者 j的左区间大于i的右区间
所以只需要两次按照端点排序,分别二分即可
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
int t, n, temp[N];
struct node {
int l, r, ln, rn;
} a[N];
bool cmpl(node a, node b) { return a.l < b.l; }
bool cmpr(node a, node b) { return a.r < b.r; }
int main() {
cin >> t;
while (t--) {
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i].l >> a[i].r;
a[i].ln = a[i].rn = 0;
}
sort(a, a + n, cmpl);
for (int i = 0; i < n; i++) {
temp[i] = a[i].l;
}
for (int i = 0; i < n; i++) {
int pos = upper_bound(temp, temp + n, a[i].r) - temp;
a[i].rn = n-pos;
}
sort(a, a + n, cmpr);
for (int i = 0; i < n; i++) {
temp[i] = a[i].r;
}
for (int i = 0; i <n; i++) {
int pos = lower_bound(temp, temp + n, a[i].l) - temp-1;
a[i].ln = pos + 1;
}
int res = 0x3f3f3f3f;
for (int i = 0; i < n; i++) {
res = min(a[i].ln + a[i].rn, res);
}
cout << res << endl;
}
return 0;
}