赞
踩
公元 N N N年在第几个世纪中?
一个世纪是由 100 100 100个年份组成的一个区间。如, 1 1 1世纪为 [ 1 , 100 ] [1,100] [1,100]年, 2 2 2世纪为 [ 101 , 200 ] [101,200] [101,200]年,……
1 ≤ N ≤ 3000 1\le N\le 3000 1≤N≤3000
N N N
将答案输出为一个整数。
N N N | 输出 |
---|---|
2021 2021 2021 | 21 21 21 |
200 200 200 | 2 2 2 |
根据本题条件我们可以推出:公元 N N N年在世纪 ⌈ N 100 ⌉ \lceil \frac N {100}\rceil ⌈100N⌉。
#include <cstdio>
using namespace std;
int main()
{
int n;
scanf("%d", &n);
printf("%d\n", n % 100 == 0? n / 100: n / 100 + 1);
return 0;
}
对于整数 N N N,执行 K K K次如下操作:
1
≤
N
≤
1
0
5
1\le N\le 10^5
1≤N≤105
1
≤
K
≤
20
1\le K\le 20
1≤K≤20
N K N~K N K
输出最终的 N N N。
N N N | K K K | 输出 |
---|---|---|
2021 2021 2021 | 4 4 4 | 50531 50531 50531 |
40000 40000 40000 | 2 2 2 | 1 1 1 |
8691 8691 8691 | 20 20 20 | 84875488281 84875488281 84875488281 |
本题我们按照题意模拟即可,但我们需要证明答案不会超过
2
63
−
1
2^{63}-1
263−1,这样才能使用long long
:
00
结尾,就证明了它是
200
200
200的倍数。#include <cstdio>
using namespace std;
int main()
{
long long n;
int k;
scanf("%lld%d", &n, &k);
while(k--)
n = n % 200LL == 0LL? n / 200LL: n * 1000LL + 200LL;
printf("%lld\n", n);
return 0;
}
给定序列 A = ( A 1 , A 2 , … , A N ) A=(A_1,A_2,\dots,A_N) A=(A1,A2,…,AN),找到符合下列条件的所有 ( i , j ) (i,j) (i,j):
2
≤
N
≤
2
×
1
0
5
2\le N\le 2\times 10^5
2≤N≤2×105
1
≤
A
i
≤
1
0
9
1\le A_i\le 10^9
1≤Ai≤109
N
N
N
A
1
A
2
…
A
N
A_1~A_2~\dots~A_N
A1 A2 … AN
A A A | 输出 |
---|---|
( 123 , 223 , 123 , 523 , 200 , 2000 ) (123,223,123,523,200,2000) (123,223,123,523,200,2000) | 4 4 4 |
( 1 , 2 , 3 , 4 , 5 ) (1,2,3,4,5) (1,2,3,4,5) | 0 0 0 |
( 199 , 100 , 200 , 400 , 300 , 500 , 600 , 200 ) (199,100,200,400,300,500,600,200) (199,100,200,400,300,500,600,200) | 9 9 9 |
首先,最容易想到的
O
(
n
2
)
\mathcal O(n^2)
O(n2)的暴力算法肯定不行,因为
2
≤
N
≤
2
×
1
0
5
2\le N\le 2\times 10^5
2≤N≤2×105。
我们考虑用桶优化:
我们有
200
200
200个桶,分别如下:
桶的编号 | 元素 1 1 1 | 元素 2 2 2 | 元素 3 3 3 | 元素 4 4 4 | …… | 元素除以 200 200 200的余数 |
---|---|---|---|---|---|---|
0 0 0 | 0 0 0 | 200 200 200 | 400 400 400 | 600 600 600 | …… | 0 0 0 |
1 1 1 | 1 1 1 | 201 201 201 | 401 401 401 | 601 601 601 | …… | 1 1 1 |
2 2 2 | 2 2 2 | 202 202 202 | 402 402 402 | 602 602 602 | …… | 2 2 2 |
…… | …… | …… | …… | …… | …… | …… |
198 198 198 | 198 198 198 | 398 398 398 | 598 598 598 | 798 798 798 | …… | 198 198 198 |
199 199 199 | 199 199 199 | 399 399 399 | 599 599 599 | 799 799 799 | …… | 199 199 199 |
这时,我们发现,每个桶中的每个元素都能与这个同种的其他元素组成一对,所以我们只要在将元素加入桶中前将答案加上桶目前的大小即可。 |
总时间复杂度 O ( n ) \mathcal O(n) O(n)。
我们的桶中不需要真正的元素,只需要记录桶的大小即可。
注意:答案的数据类型一定要用long long
!
#include <cstdio> #define MOD 200 using namespace std; int cnt[MOD]; int main() { int n; scanf("%d", &n); long long ans = 0LL; while(n--) { int x; scanf("%d", &x); ans += cnt[x %= MOD] ++; } printf("%lld\n", ans); return 0; }
给定序列 A = ( A 1 , A 2 , … , A N ) A=(A_1,A_2,\dots,A_N) A=(A1,A2,…,AN)。你要从中选出两个子序列 B B B和 C C C(下标不同,不要求连续),使得 ∑ B ≡ ∑ C ( m o d 200 ) \sum B\equiv \sum C\pmod{200} ∑B≡∑C(mod200)。
2
≤
N
≤
200
2\le N\le 200
2≤N≤200
1
≤
A
i
≤
1
0
9
1\le A_i\le 10^9
1≤Ai≤109
N
N
N
A
1
A
2
…
A
N
A_1~A_2~\dots~A_N
A1 A2 … AN
如果没有合法的
B
B
B和
C
C
C,输出No
。
如果有合法的
B
B
B和
C
C
C,按下列格式输出,其中
x
x
x为
B
B
B的长度、
y
y
y为
C
C
C的长度,
B
′
B'
B′为
B
B
B中元素对应的下标,
C
′
C'
C′为
C
C
C中元素对应的下标:
Yes
\text{Yes}
Yes
x
B
1
′
B
2
′
…
B
x
′
x~B'_1~B'_2~\dots~B'_x
x B1′ B2′ … Bx′
y
C
1
′
C
2
′
…
C
y
′
y~C'_1~C'_2~\dots~C'_y
y C1′ C2′ … Cy′
略,请自行前往AtCoder查看
我们可以证明,只要 N ≥ 8 N\ge 8 N≥8,那么就一定有解。证明如下:
当
N
<
8
N<8
N<8时,我们暴力枚举所有可能;
当
N
≥
8
N\ge8
N≥8时,我们暴力枚举其中任意
8
8
8个元素组成的所有可能即可找到解。
#include <cstdio> #include <vector> #define maxn 10 #define MOD 200 using namespace std; int a[maxn]; vector<int> bkt[MOD]; inline void print(const vector<int>& v) { printf("%llu", v.size()); for(int x: v) printf(" %d", x + 1); putchar('\n'); } int main() { int n; scanf("%d", &n); if(n > 8) n = 8; for(int i=0; i<n; i++) scanf("%d", a + i); int lim = 1 << n; for(int st=0; st<lim; st++) { int s = 0; vector<int> pos; for(int i=0; i<n; i++) if(st >> i & 1) s = (s + a[i]) % MOD, pos.push_back(i); if(!bkt[s].empty()) { puts("Yes"); print(bkt[s]); print(pos); return 0; } else bkt[s] = pos; } puts("No"); return 0; }
有 N 3 N^3 N3个三元组 ( i , j , k ) (i,j,k) (i,j,k)( 1 ≤ i , j , k ≤ N 1\le i,j,k\le N 1≤i,j,k≤N),按如下排序:
求第 K K K个 ( i , j , k ) (i,j,k) (i,j,k)。
1
≤
N
≤
1
0
6
1\le N\le 10^6
1≤N≤106
1
≤
K
≤
N
3
1\le K\le N^3
1≤K≤N3
N K N~K N K
输出第 K K K个 ( i , j , k ) (i,j,k) (i,j,k),用空格分隔。
N N N | K K K | 输出 |
---|---|---|
2 2 2 | 5 5 5 | 1 2 2 1~2~2 1 2 2 |
1000000 1000000 1000000 | 1000000000000000000 1000000000000000000 1000000000000000000 | 1000000 1000000 1000000 1000000~1000000~1000000 1000000 1000000 1000000 |
9 9 9 | 47 47 47 | 3 1 4 3~1~4 3 1 4 |
由于每个三元组的和都不会超过
3
N
3N
3N,所以我们考虑暴力枚举三元组的和,这样就能快速算出第
K
K
K个三元组的和。那么,问题来了:符合
i
+
j
+
k
=
n
i+j+k=n
i+j+k=n的三元组
(
i
,
j
,
k
)
(i,j,k)
(i,j,k)(
i
,
j
,
k
i,j,k
i,j,k均不超过
N
N
N)有多少个?
这可以用容斥原理解决。首先,我们发现,上述问题实际上就是在求如下方程解的个数:
{
i
+
j
+
k
=
n
1
≤
i
,
j
,
k
≤
N
如果我们将问题改成求如下方程解的个数(注意
n
n
n和
N
N
N的区别):
{
i
+
j
+
k
=
n
1
≤
i
,
j
,
k
≤
n
这个可以用挡板法解决,在
n
−
1
n-1
n−1个位置上任选
2
2
2个插入挡板,挡板分开的就是
i
,
j
,
k
i,j,k
i,j,k,则公式为
C
n
−
1
2
C_{n-1}^2
Cn−12。我们设
f
(
n
)
=
f(n)=~
f(n)= 上述方程解的个数(
C
n
−
1
2
=
(
n
−
1
)
(
n
−
2
)
C_{n-1}^2=(n-1)(n-2)
Cn−12=(n−1)(n−2)),则总方程解的个数为
f
(
n
)
f(n)
f(n)。
我们考虑一个、两个(不可能有三个)数大于
N
N
N的情况,这样
{
i
+
j
+
k
=
n
1
≤
i
,
j
,
k
≤
N
计算 f ( n ) f(n) f(n)时注意特判 n ≤ 2 n\le 2 n≤2的情况,否则可能会出现负数!
#include <cstdio> using namespace std; using LL = long long; int n; inline int max(int x, int y) { return x > y? x: y; } inline int min(int x, int y) { return x < y? x: y; } inline LL f(LL n) { return n-- > 2? n * (n - 1LL) >> 1LL: 0LL; } inline LL count(int s) { return f(s) - 3 * (f(s - n) - f(s - (n << 1))); } int main() { LL k; scanf("%d%lld", &n, &k); int lim = n * 3; for(int sum=3; sum<=lim; sum++) { LL cnt = count(sum); if(k > cnt) { k -= cnt; continue; } for(int a=1; a<=n; a++) { int minb = max(1, sum - a - n), maxb = min(n, sum - a - 1); if(minb > maxb) continue; int num = maxb - minb + 1; if(k <= num) { int b = minb + k - 1; int c = sum - a - b; printf("%d %d %d\n", a, b, c); return 0; } k -= num; } } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。