A. Favorite Sequence
题目链接
水题,只要按题目要求输出即可。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define MULTICASE int _;cin >> _;while(_ --)
#define IO ios::sync_with_stdio(false);\
cin.tie(NULL);\
cout.tie(NULL);
const int N = 400;
int a[N];
main(){
IO
MULTICASE
{
int n;
cin >> n;
for(int i = 1; i <= n;i ++)
{
cin >> a[i];
}
int t = 1, s = n + 1;
for(int i = 1;i <= n;i ++)
{
cout << a[t] << ' ';
t = s - t;
if(i % 2 == 0)t ++;
}
cout<< endl;
}
}
B. Last Year’s Substring
题目链接
判断删去连续一段后能否变成2020,实际上考虑该字符串的头和尾能否构成2020即可,这里写的比较繁琐。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define MULTICASE int _;cin >> _;while(_ --)
#define IO ios::sync_with_stdio(false);\
cin.tie(NULL);\
cout.tie(NULL);
main(){
IO
MULTICASE
{
string str;
int n;
cin >> n >> str;
int t1;
bool isok = false;
int len = str.size();
if(str.substr(0, 4) == "2020")
isok = true;
if(str.substr(0, 3) == "202" && len - 1 >= 0 && str[len - 1] == '0')
isok = true;
if(str.substr(0, 2) == "20" && len - 2 >= 0 && str.substr(len - 2, 2) == "20")
isok = true;
if(str[0] == '2' && len - 3 >= 0 && str.substr(len - 3, 3) == "020")
isok = true;
if(len - 4 >= 0 && str.substr(len - 4, 4) == "2020")
isok = true;
if(isok)cout << "YES";
else cout << "NO";
cout << endl;
}
}
C. Unique Number
题目链接
当
x
<
10
x<10
x<10时,直接输出
x
x
x即可。
当
x
≥
10
x≥10
x≥10时,我们可以列出几项得到规律。
x | s |
---|---|
10 | 19 |
11 | 29 |
… | … |
17 | 89 |
18 | 189 |
… | … |
24 | 789 |
25 | 1789 |
规律便是先将第一位不断加
1
1
1,等第一位与第二位相同时再在最前面插入一个
1
1
1。
注意到当
x
>
45
x>45
x>45时,我们无法求出这个数,编程即可。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define MULTICASE int _;cin >> _;while(_ --)
#define IO ios::sync_with_stdio(false);\
cin.tie(NULL);\
cout.tie(NULL);
main(){
IO
MULTICASE
{
int x;
cin >> x;
if(x <= 9)
cout << x << endl;
else
{
int t = 1;
if(x > 45)
{
cout << -1 << endl;
continue;
}
set<int> st;
st.insert(9);
x -= 9;
while(x --)
{
if(st.count(t))t = 1;
if(st.count(t - 1))
st.erase(t - 1);
st.insert(t);
t ++;
}
for(auto i : st)
cout << i;
cout << endl;
}
}
}
D. Add to Neighbour and Remove
题目链接
这道题让我想了20分钟左右,想出来了一个比较巧妙的方法。
要使数列中的元素相同,他们的和就一定能被合并后的数组中的每一项整除(当然,合并后的数组的每一项都相同),我们就可以先将它们的和求出,然后对它求出所有的因数,时间复杂度约为
O
(
∑
a
i
)
O(\sqrt{∑a_i})
O(∑ai),考虑到
a
i
≤
1
e
5
,
∑
n
≤
3000
a_i≤1e5,∑n≤3000
ai≤1e5,∑n≤3000,最坏情况下大概做
2
e
4
2e4
2e4次左右的判断。
求出所有因子后,我们可以将他们从小到大排个序,将每一个因子作为合并后数组中的每一项的和,对于每一个因子,遍历数组后我们就可以判断是否能够组成将这个因子作为每一项的数列。这里的时间复杂度约为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)。
我们就可以较为快捷地得出这个问题的答案。
由于
∑
n
≤
3000
∑n≤3000
∑n≤3000,我们同时也可以用
O
(
n
2
)
O(n^2)
O(n2)的较为暴力的方法得出问题的解,枚举将前
i
i
i(
i
∈
[
1
,
n
]
i∈[1,n]
i∈[1,n])项合并成一项作为合并后数列的一项,之后判断也可。
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define MULTICASE int _;cin >> _;while(_ --)
#define IO ios::sync_with_stdio(false);\
cin.tie(NULL);\
cout.tie(NULL);
#define int long long
const int N = 3030;
int a[N];
main(){
IO
MULTICASE
{
int n;
cin >> n;
for(int i = 1;i <= n;i ++)
cin >> a[i];
int ans = accumulate(a + 1, a + n + 1, 0);
vector<int> v;
for(int i = 1; i * i <= ans;i ++)
{
if(ans % i == 0)
{
v.pb(i);
if(i * i != ans)
v.pb(ans / i);
}
}
sort(v.begin(), v.end());
bool ok = 1, done = 0;
for(int i = 0;i < v.size() ;i ++)
{
int sum = 0;
ok = 1;
for(int j = 1;j <= n;j ++)
{
sum += a[j];
if(sum == v[i])sum = 0;
if(sum > v[i])
{
ok = false;
break;
}
}
if(ok)
{
cout << n - ans / v[i] << endl;
done = 1;
break;
}
}
if(!done)
cout << n - 1 << endl;
}
}
E1. Close Tuples (easy version)
题目链接
一个较为简单的组合数问题,由于题目中数组的位置对答案产生不了影响,我们就可以较为快捷地先将数组从小到大排个序,然后从第三个位置开始,用lower_bound来找出该值-2的那个下标最小的位置,设他们的间距为
x
x
x,则有
s
u
m
=
s
u
m
+
x
×
(
x
−
1
)
/
2
sum=sum+x×(x-1)/2
sum=sum+x×(x−1)/2
即可。
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define int long long
#define MULTICASE int _;cin >> _;while(_ --)
#define IO ios::sync_with_stdio(false);\
cin.tie(NULL);\
cout.tie(NULL);
const int N = 3030;
int a[N];
main(){
IO
MULTICASE
{
int n;
cin >> n;
for(int i = 1;i <= n;i ++)
{
cin >> a[i];
}
int ans = 0;
sort(a + 1, a + n + 1);
for(int i = 3;i <= n;i ++)
{
int x = lower_bound(a + 1, a + n + 1, a[i] - 2) - a;
if(i - x < 2)continue;
ans += (i - x - 1) * (i - x) / 2;
}
cout << ans << '\n';
}
}
E2. Close Tuples (hard version)
题目链接
题目大致跟E1差不多。
考虑到
m
≤
100
m≤100
m≤100,我们可以建立一个宽度为100+的杨辉三角。当然也可以预处理阶乘来求得组合数,设他们的间距为
x
x
x,公式即为
a
n
s
=
(
a
n
s
+
(
x
m
−
1
)
)
m
o
d
1
e
9
+
7
ans = (ans + \tbinom{x}{m-1})\mod 1e9+7
ans=(ans+(m−1x))mod1e9+7
编程得:
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define int long long
#define MULTICASE int _;cin >> _;while(_ --)
#define IO ios::sync_with_stdio(false);\
cin.tie(NULL);\
cout.tie(NULL);
#define mod 1000000007
const int N = 200200;
int A[N];
int B[N];
//大佬的模板 QAQ
int Ext_Gcd(int a, int b, int &x, int &y)
{
if(b==0){
x=1;
y=0;
return a;
}
int d = Ext_Gcd(b, a%b, y, x);
y-=a/b*x;
return d;
}
int Inv(int a, int n)
{
int x,y;
int d = Ext_Gcd(a,n,x,y);
if(d == 1)
return ((x%n)+n)%n;
return -1;
}
int C(int a, int b)
{
if(a < b)
return 0;
return (A[a] * B[b] %mod)*B[a-b]%mod;
}
void get()
{
for(int i=0;i< N;i++)
B[i] = Inv(A[i],mod);
}
void Init()
{
A[0] = 1;
for(int i=1; i<=N; i++){
A[i] = (A[i - 1] * i ) % mod;
}
get();
}
int a[N];
main(){
IO
Init();
MULTICASE
{
int n, m, k;
cin >> n >> m >> k;
for(int i = 1;i <= n;i ++)
cin >> a[i];
sort(a + 1, a + n + 1);
int ans = 0;
for(int i = m;i <= n;i ++)
{
int x = lower_bound(a + 1, a + n + 1, a[i] - k) - a;
if(i - x < m - 1)continue;
ans = (C(i - x, m - 1) + ans) % mod;
}
cout << ans << '\n';
}
}