Codeforces Round #640 Div. 4
A. Sum of Round Numbers
思路:
应该都会做吧,懒,不写了
代码:
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
typedef vector<int> vi;
typedef queue<int> qi;
typedef long long ll;
typedef pair<int, int> pii;
typedef double db;
int main()
{
int t; cin >> t;
while (t --)
{
int n; cin >> n;
vi ans;
int t = 1;
while (n)
{
if(n % 10 != 0)
ans.pb(n % 10 * t);
t *= 10;
n /= 10;
}
cout << ans.size() << endl;
for (auto &x : ans) cout << x << " ";
cout << endl;
}
return 0;
}
B. Same Parity Summands
思路:
两种情况:
- 都是奇数,k - 1个1,剩下一个数是 n - (k - 1)
- 都是偶数,k - 1个2,剩下一个数是n - (k - 1) * 2
- 判断上面两个是否合法,合法就输出yes,不然就no
代码:
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
typedef vector<int> vi;
typedef queue<int> qi;
typedef long long ll;
typedef pair<int, int> pii;
typedef double db;
int main()
{
int t; cin >> t;
while (t --)
{
int n, k; cin >> n >> k;
if(n > k - 1 && (n - (k - 1)) % 2 == 1)
{
puts("YES");
for (int i = 1; i < k; ++ i) cout << 1 << " ";
cout << n - (k - 1) << endl;
}
else if(n > (k - 1) * 2 && (n - (k - 1) * 2) % 2 == 0)
{
puts("YES");
for (int i = 1; i < k; ++ i) cout << 2 << " ";
cout << n - (k - 1) * 2 << endl;
}
else puts("NO");
}
return 0;
}
C. K-th Not Divisible by n
思路:
看看题目给得样例,可以看出每个n个数里面就有n-1个是不能整除n的,所以
x
∗
n
x*n
x∗n有
x
∗
(
n
−
1
)
x*(n-1)
x∗(n−1)合法的,所以肯定存在一个x使得
x
∗
(
n
−
1
)
≤
k
x*(n-1)\leq k
x∗(n−1)≤k 而
(
x
+
1
)
∗
(
n
−
1
)
>
k
(x+1)*(n-1)>k
(x+1)∗(n−1)>k,所以第
k
k
k个数就在这两者之间,二分找到这个x,就知道第
k
k
k个数了。
特判这总情况:
x
∗
n
=
k
x*n=k
x∗n=k,则答案就是
n
∗
k
−
1
n*k-1
n∗k−1
代码:
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
typedef vector<int> vi;
typedef queue<int> qi;
typedef long long ll;
typedef pair<int, int> pii;
typedef double db;
int main()
{
int t; cin >> t;
while (t --)
{
ll n, k; cin >> n >> k;
ll l = 0, r = 1e9;
while (l < r)
{
ll mid = (l + r + 1) >> 1;
if(mid * (n - 1) <= k) l = mid; else r = mid - 1;
}
int f = 0;
if(k - (l * (n - 1)) == 0) f = 1;
cout << l * n + (k - (l * (n - 1))) - f << endl;
}
return 0;
}
D. Alice, Bob and Candies
思路:
额。模拟题,这个没啥好说的了,模拟Alice吃一口,Bob吃一口,一直吃下去就行了
代码:
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
typedef vector<int> vi;
typedef queue<int> qi;
typedef long long ll;
typedef pair<int, int> pii;
typedef double db;
const int N = 2e5 + 5;
int A[N];
int main()
{
int t; scanf("%d", &t);
while (t --)
{
int moves = 0, a = 0, b = 0;
int n; scanf("%d", &n);
for (int i = 1; i <= n; ++ i) scanf("%d", &A[i]);
int pa = 1, pb = n, sa = 0, sb = 0, f = 1;
while (pa <= pb)
{
if(f == 1)
{
sa = 0;
while (sa <= sb && pa <= pb)
{
sa += A[pa ++];
}
a += sa;
f = 0;
// cout << sa << endl;
}
else
{
sb = 0;
while (sb <= sa && pa <= pb)
{
sb += A[pb --];
}
b += sb;
f = 1;
// cout << "sb : " <<sb << endl;
}
++ moves;
}
printf("%d %d %d\n", moves, a, b);
}
return 0;
}
E. Special Elements
解法1
思路:
用set维护前缀和,对于每i位,然后对于每个特殊元素,查找set中是否存在值等于
s
u
m
[
i
]
−
x
sum[i]-x
sum[i]−x的前缀和
s
u
m
[
j
]
,
j
<
i
−
1
sum[j],j<i-1
sum[j],j<i−1,则可以判断了,时间时间复杂度为
O
(
n
∗
p
∗
l
o
g
(
n
)
)
O(n*p*log(n))
O(n∗p∗log(n))
代码:
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
typedef vector<int> vi;
typedef queue<int> qi;
typedef long long ll;
typedef pair<int, int> pii;
typedef double db;
const int N = 8e3 + 5;
int a[N], sum[N], b[N];
int ct[N];
set<int> m;
int main()
{
int t; cin >> t;
while (t --)
{
m.clear();
memset(ct, 0, sizeof(ct));
int n; cin >> n;
for (int i = 1; i <= n; ++ i)
{
cin >> a[i];
b[i] = a[i];
ct[a[i]] ++;
}
sort (b + 1, b + n + 1);
int p = unique(b + 1, b + n + 1) - b;
int ans = 0;
for (int i = 1; i <= n; ++ i)
{
sum[i] = sum[i - 1] + a[i];
for (int j = 1; j < p; ++j)
{
if(!ct[b[j]]) continue;
if(m.size() && m.find(sum[i] - b[j]) != m.end())
{
ans += ct[b[j]];
ct[b[j]] = 0;
}
}
m.insert(sum[i - 1]);
}
cout << ans << endl;
}
return 0;
}
解法2
思路:
n
n
n最大是
8000
8000
8000,所以
n
2
n^2
n2的做法也是可以的,枚举所有长度大于
1
1
1的区间,可以利用前缀和
O
(
1
)
O(1)
O(1)求出区间和,最后扫一遍就可以了,时间复杂度为
O
(
n
2
)
O(n^2)
O(n2)
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 8e3 + 5;
bool v[N];
int a[N], s[N];
int main()
{
int t; cin >> t;
while (t --)
{
memset(v, 0, sizeof(v));
int n; cin >> n;
for (int i = 1; i <= n; ++ i)
{
cin >> a[i];
s[i] = s[i - 1] + a[i];
}
for (int l = 1; l <= n; ++ l)
for (int r = l + 1; r <= n; ++ r)
if(s[r] - s[l - 1] <= 8000)
v[s[r] - s[l - 1]] = 1;
int ans = 0;
for (int i = 1; i <= n; ++ i) ans += v[a[i]];
cout << ans << endl;
}
return 0;
}
F. Binary String Reconstruction
比赛的时候时间不够了,没开出来,吐血。
思路:
直觉感觉就是这个字符串就是这样,左边全是0,中间就是0101这样,右边都是1,只需控制好数量就行了。
- n 1 > 0 n1>0 n1>0 的情况,就是上面说的那种
-
n
1
=
0
n1 = 0
n1=0的情况,要不就是
n
0
+
1
n_0+1
n0+1个0,要不就是
n
2
+
1
n_2+1
n2+1个1
重点说一下第1种情况,可以先构造中间01块的数量,只构造到01…01就可以了,不要以0结尾这样后面接1会导致 n 2 n_2 n2的数量不够,剩下的一个0等到右边的所有1放完,放到最后去。然后就是左边放 n 0 n_0 n0个0,右边放 n 2 n_2 n2个1,最后特判要不放0就行了
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
typedef vector<int> vi;
typedef queue<int> qi;
typedef long long ll;
typedef pair<int, int> pii;
typedef double db;
const int N = 605;
char a[N];
int main()
{
int t; cin >> t;
while (t --)
{
int n0, n1, n2; cin >> n0 >> n1 >> n2;
if(!n1)
{
if(n0) for (int i = 0; i <= n0; ++ i) putchar('0');
if(n2) for (int i = 0; i <= n2; ++ i) putchar('1');
}
else
{
int f = 0;
if(n1 % 2 == 0) f = 1,n1 --;
int j, i;
for (i = 0, j = 200; i <= n1; ++ i, ++ j)
if(j % 2) a[j] = '1';
else a[j] = '0';
for (i = 1; i <= n2; ++ i, ++ j) a[j] = '1';
if(f) a[j ++] = '0';
a[j] = '\0';
for (i = 1, j = 199; i <= n0; ++ i, -- j) a[j] = '0';
++ j;
// puts(a + j);
for (i = j; a[i]; ++ i) putchar(a[i]);
}
puts("");
}
return 0;
}
G. Special Permutation
这种构造题有想法后真的简单,可能很多人被E题卡了,都没时间做这题,才导致过题人数比较少。
思路:
想一想这样一个序列
1
,
3
,
5...
(
2
∗
n
−
1
)
1,3,5...(2*n-1)
1,3,5...(2∗n−1) 和
2
,
4
,
6..
(
2
∗
n
)
2,4,6..(2*n)
2,4,6..(2∗n)两个序列,前一个元素和后一元素之差都是2,这是符合题目要求的,所以可以把第2块调个顺序,然后把它两连在一起,这样就只有连接处不合法。
- 若 n n n是偶数,连接处是这样的 . . . ( 2 k − 3 ) , ( 2 k − 1 ) , ( 2 k ) , ( 2 k − 2 ) . . . ...(2k-3),(2k-1),(2k),(2k-2)... ...(2k−3),(2k−1),(2k),(2k−2)...,调换 ( 2 k − 3 ) (2k-3) (2k−3)和 ( 2 k − 1 ) (2k-1) (2k−1)就可以了
- 若 n n n是奇数,连接处是这样的 . . . ( 2 k − 1 ) , ( 2 k + 1 ) , ( 2 k ) , ( 2 k − 2 ) . . . ...(2k-1),(2k+1),(2k),(2k-2)... ...(2k−1),(2k+1),(2k),(2k−2)...,调换 ( 2 k − 2 ) (2k-2) (2k−2)和 ( 2 k ) (2k) (2k)就可以了
代码:
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
typedef vector<int> vi;
typedef queue<int> qi;
typedef long long ll;
typedef pair<int, int> pii;
typedef double db;
const int N = 1e3 + 5;
int a[N];
int main()
{
int t; cin >> t;
while (t --)
{
int n; cin >> n;
if(n < 4)
{
puts("-1");
continue;
}
int num = (n + 1) / 2;
for (int i = 1, j = 1; i <= num; ++ i, j += 2) a[i] = j;
// swap(a[num], a[num - 1]);
for (int i = num + 1, j = 2; i <= n; ++ i, j += 2) a[i] = j;
reverse(a + num + 1, a + n + 1);
if(n % 2 == 0) swap(a[num], a[num - 1]);
else swap(a[num + 1], a[num + 2]);
for (int i = 1; i <= n; ++ i) printf("%d%c", a[i], i == n ? '\n' : ' ');
}
return 0;
}