A . A. A.
题意: 给定长度为 [ 1 , n ] [1,n] [1,n]的木棍各一个,问若干次拼接后使得长度相同的木棍数量最大是多少。
题解: 当 n n n是偶数时,即 1 1 1和 n n n拼接, 2 2 2和 n − 1 n-1 n−1拼接,最终有 ⌊ n 2 ⌋ \lfloor \frac{n}{2} \rfloor ⌊2n⌋个。当 n n n为奇数时,那么 n = ( 1 + n − 1 ) = ( 2 + n − 2 ) n=(1+n-1)=(2+n-2) n=(1+n−1)=(2+n−2),此时 n − 1 n-1 n−1是偶数,可以构造出 ⌊ n − 1 2 ⌋ \lfloor \frac{n-1}{2} \rfloor ⌊2n−1⌋个 n n n出来,那么总共就是 ⌊ n − 1 2 ⌋ + 1 \lfloor \frac{n-1}{2} \rfloor+1 ⌊2n−1⌋+1个。两者结合就是 ⌊ n + 1 2 ⌋ \lfloor \frac{n+1}{2} \rfloor ⌊2n+1⌋。
代码:
#include
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
void solve() {
int n;
scanf("%d", &n);
printf("%d\n", n + 1 >> 1);
}
int main()
{
int T = 1;
scanf("%d", &T);
while(T--) {
solve();
}
}
B . B. B.
题意: 给定长度为 k k k的列,行数不限,枚举长度为 n n n的格子连续摆放形式有多少种。(即对于任意一个摆放的格子其上下左右四个方向至少也要有一个格子被摆放)
题解: 当 n ≤ k n \leq k n≤k,此时只有一种。注意这一种是指列为 [ n , r ] [n,r] [n,r]都只算一种。
那么考虑 n > k n> k n>k,此时必然有一行是摆满的,否则还是不可能存在连续摆放形式。所以我们枚举对 k k k取模的部分。
1. 1. 1. 如果为 0 0 0,那么必然是摆满两行或以上,我们枚举 r o w row row为 n n n在列为 k k k的情况下摆满的行数( r o w ≥ 2 row\geq 2 row≥2),那么我们必然可以找出一行来枚举,即我们选择的满行是 [ 2 , r o w ] [2,row] [2,row]。
那么对第 1 1 1行和 r o w + 1 row+1 row+1行存在以下情况。
1 1 1 | r o w + 1 row+1 row+1 |
---|---|
k k k | 0 0 0 |
k − 1 k-1 k−1 | 1 1 1 |
k − 2 k-2 k−2 | 2 2 2 |
. . . ... ... | . . . ... ... |
2 2 2 | k − 2 k-2 k−2 |
1 1 1 | k − 1 k-1 k−1 |
0 0 0 | k k k |
这里的 k , 0 k,0 k,0和 0 , k 0,k 0,k两种情况是一样的形状,故共 k k k种
2. 2. 2. 如果大于 0 0 0,那么共有 r o w = ⌈ n k ⌉ row=\lceil \frac{n}{k} \rceil row=⌈kn⌉行。此时我们认为 [ 2 , r o w ] [2,row] [2,row]是被填满的,第一行没被填满,那么第一行有 s u r p l u s = n % k surplus=n\%k surplus=n%k个可摆放。情况与 1 1 1类似,如下:
1 1 1 | r o w + 1 row+1 row+1 |
---|---|
s u r p l u s surplus surplus | 0 0 0 |
s u r p l u s − 1 surplus-1 surplus−1 | 1 1 1 |
s u r p l u s − 2 surplus-2 surplus−2 | 2 2 2 |
. . . ... ... | . . . ... ... |
2 2 2 | s u r p l u s − 2 surplus-2 surplus−2 |
1 1 1 | s u r p l u s − 1 surplus-1 surplus−1 |
0 0 0 | s u r p l u s surplus surplus |
所以共 s u r p l u s + 1 surplus+1 surplus+1种。
再加上 [ n ≤ r ] [n\leq r] [n≤r]即可。
代码:
#include
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
void solve() {
ll n, r;
scanf("%lld%lld", &n, &r);
ll res = 0;
if(n <= r) res++;
ll x = min(n - 1, r);
res += (1 + x) * x / 2;
printf("%lld\n", res);
}
int main()
{
int T = 1;
scanf("%d", &T);
while(T--) {
solve();
}
}
C . C. C.
题意:
给定 a a a块香草饼干, b b b块巧克力饼干, n n n个一类人, m m m个二类人。
第一类人会选择剩余饼干更多的,比较考虑可持久化。而二类人喜欢唱反调,选择当前更少的。
题解: 必然是先让一类人吃到两种饼干一样多。然后按照 2 , 1 , 2 , 1 2,1,2,1 2,1,2,1这样的顺序来吃饼干,保证可持久化(即数量更少的饼干不会被先吃完)。所以只要考虑初始情况下数量更少的饼干是否可以满足二类人的需求。当然,两种饼干数量和少于人数那么对于这两种人都会生气。
代码:
#include
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
void solve() {
ll a, b, n, m;
scanf("%lld%lld%lld%lld", &a, &b, &n, &m);
ll Mi = min(a, b);
if(Mi >= m && a + b >= n + m) puts("Yes");
else puts("No");
}
int main()
{
int T = 1;
scanf("%d", &T);
while(T--) {
solve();
}
}
D . D. D.
题意:
给定 n × n n\times n n×n的矩阵,每次在矩阵中填 k k k个 1 1 1,其余位置填 0 0 0,构造出可以使得 x = ( m a x ( R ) − m i n ( R ) ) 2 + ( m a x ( C ) − m i n ( C ) ) 2 x=(max(R)-min(R))^2+(max(C)-min(C))^2 x=(max(R)−min(R))2+(max(C)−min(C))2最小的矩阵。
题解:
完全按照对角线来构造,貌似是某种三角形的构造形式,当越界了就取模回到矩阵中的合法位置即可。
代码:
#include
using namespace std;
typedef long long ll;
const int N = 300 + 10;
char s[N][N];
void solve() {
int n, m;
scanf("%d%d", &n, &m);
for(int k = 0; k < n; k++)
for(int i = k, j = 0; j < n; i++, j++) {
if(m > 0) s[i % n][j] = '1', m--;
else s[i % n][j] = '0';
}
for(int i = 0; i < n; i++) s[i][n] = '\0';
int Maxr = 0, Minr = n, Maxc = 0, Minc = n;
for(int i = 0; i < n; i++) {
int temp = 0;
for(int j = 0; j < n; j++)
temp += s[i][j] - '0';
Maxr = max(Maxr, temp);
Minr = min(Minr, temp);
}
for(int j = 0; j < n; j++) {
int temp = 0;
for(int i = 0; i < n; i++)
temp += s[i][j] - '0';
Maxc = max(Maxc, temp);
Minc = min(Minc, temp);
}
int res = (Maxr - Minr) * (Maxr - Minr) + (Maxc - Minc) * (Maxc - Minc);
printf("%d\n", res);
for(int i = 0; i < n; i++)
printf("%s\n", s[i]);
}
int main()
{
int T = 1;
scanf("%d", &T);
while(T--) {
solve();
}
}
E . E. E.
题意: 给定 n n n个怪兽和一个质数 p p p,及每个怪兽拥有的糖果数 a i a_i ai。你可以任意选择打怪的先后顺序,如果当前你手中有 n o w now now个糖果,当 n o w ≥ a i now\geq a_i now≥ai,说明你打败了这个怪兽,且糖果数加 1 1 1,否则你就不能打败当前这个怪兽。 f ( x ) f(x) f(x)为初始手上有 x x x个糖果时,成功打败所有怪兽的先后顺序数,若 f ( x ) % p ≠ 0 f(x)\%p\neq0 f(x)%p=0,则 x x x为 g o o d good good,问有多少 x x x是 g o o d good good。
保证 p ≤ n ≤ 1 0 5 p\leq n\leq10^5 p≤n≤105, 1 ≤ a i ≤ 1 0 9 1\leq a_i\leq 10^9 1≤ai≤109
来自 c o d e f o r c e s codeforces codeforces评论区的奇妙解法:传送门 1≤cnt[x+i]−i<p 1≤cnt[x+i]−i<p
题解: 这题有很多种做法,但重心是要注意到当选择了初始糖果数为 x x x时,打第 i + 1 i+1 i+1个怪兽时,你拥有的糖果数为 x + i x+i x+i, ( i ∈ [ 0 , n ) ) (i\in[0,n)) (i∈[0,n))。
设 c n t [ n o w ] cnt[now] cnt[now]为拥有糖果数小于等于 n o w now now的怪兽数,所以要保证 1 ≤ c n t [ x + i ] − i < p 1\leq cnt[x+i]-i
那么必然有 x ∈ [ l o w , h i g h ] x\in[low,high] x∈[low,high],满足对 ∀ i ∈ [ 0 , n ) \forall i\in[0,n) ∀i∈[0,n),都有 1 ≤ c n t [ x + i ] − i < p 1\leq cnt[x+i]-i
那么问题就转换为了求 l o w low low与 h i g h high high
首先对 a a a从小到大排序:
1 1 1. 对于 l o w low low,必然有 l o w + i ≥ a i low+i\geq a_i low+i≥ai,故 l o w ≥ a i − i low\geq a_i-i low≥ai−i,即 l o w ≥ m a x ( a i − i ) low\geq max(a_i-i) low≥max(ai−i),这保证了整个过程中不会出现对于 c n t [ l o w + i ≤ 0 cnt[low+i\leq0 cnt[low+i≤0的情况。
2 2 2. 对于 h i g h high high,必然有 h i g h + i < a i + p − 1 high+i
代码:
#include
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int n, p;
int q[N];
void solve() {
scanf("%d%d", &n, &p);
for(int i = 0; i < n; i++) scanf("%d", &q[i]);
sort(q, q + n);
int l = 0, r = 1e9;
for(int i = 0; i < n; i++) l = max(l, q[i] - i);
for(int i = 0; i + p - 1 < n; i++) r = min(r, q[i + p - 1] - i - 1);
if(l > r) puts("0");
else {
printf("%d\n", r - l + 1);
for(int i = l; i <= r; i++) printf("%d%c", i, " \n"[i == r]);
}
}
int main()
{
int T = 1;
//scanf("%d", &T);
while(T--) {
solve();
}
}