Codeforces Round #714 (Div. 2) 游记
次阅读
6 min read
题目质量棒极了!!!乍一看很不可做,仔细想想问题就迎刃而解,没有一道是秒杀的。
A
求一个 的排列使有 个山峰。
先按 的顺序排好,然后 和 交换就可以产生一个山峰,而这种方案肯定能尽可能多的产生山峰。
#include <cstdio>
#include <algorithm>
int T, n, k, a[105];
int main() {
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &k);
if(k > (n+1)/2-1) {
puts("-1");
continue;
}
for(int i = 1; i <= n; i++) a[i] = i;
for(int i = 2, cnt = 0; i <= n && cnt < k; i += 2, cnt += 1)
std::swap(a[i], a[i+1]);
for(int i = 1; i <= n; i++) printf("%d ", a[i]);
puts("");
}
return 0;
}
B
一列数,从任意一点断开,若左边的全部
and
起来和右边的全部and
起来都一样就说它是好的,问将输入的数列任意打乱有多少个是好的。
一看是没有什么思路的。
仔细想想可以发现,那些哪一位其它数有一而它这一位是 的都得放在前后,不然的话在它前面断开就会一边有这样一位没有边为 而另一边变为 了, 不能称为好的序列, 所以这样的选俩放首尾,其它的中间随便排就可以了。
代码还是有些细节的。
#include <cstdio>
#include <cstring>
#define int long long
const int N = 200005, p = 1000000007;
int a[N], T, n;
bool vis[N];
signed main() {
scanf("%lld", &T);
while(T--) {
scanf("%lld", &n);
for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
memset(vis, 0, sizeof vis);
bool twt = 0, did = 0;
for(int i = 0; i <= 30; i++) {
bool flag = 0, tw = 0;
for(int j = 1; j <= n; j++)
if((1ll << i) & a[j]) tw = 1;
else flag = 1;
flag = flag && tw;
if(!flag) {
for(int j = 1; j <= n; j++)
if(did && vis[j] == 0) vis[j] = 0;
else vis[j] = 1;
continue;
}
for(int j = 1; j <= n; j++)
if(((1ll << i) & a[j]) == 0ll) {
if(did && vis[j] == 0) vis[j] = 0;
else vis[j] = 1;
}
else vis[j] = 0;
did = 1;
if(twt) break;
}
if(twt) {
puts("0");
continue;
}
int cnt = 0;
for(int j = 1; j <= n; j++) cnt += vis[j];
int ans = cnt * (cnt-1) % p;
int tans = 1;
for(int i = 1; i <= n-2; i++) tans = tans * i % p;
ans = ans * tans % p;
printf("%lld\n", ans);
}
return 0;
}
C
把一个整数中每一个位都变为其加上一的数字,
9
变为10
, 问变 次后数字长度是多少。
可怜的孩子没看清数据范围,看成保证所有的 和不超过 , 以为这是一个简单 dp, 表示 次后 出现了几次,最后 就是答案,然后顺利 T 飞。
不过这样的 DP 还有没有救呢?枚举几个小样例发现每个数都是独立变化的,既然独立变化,那么分开考虑,发现 次后都变成 10
继续变换了,那么只要能快速处理出 10
的变化就可以快速得出所有的变化。
一开始我一直想着有啥数学方法可做,后来一看,直接预处理一遍把所有次数以后的变换处理完不就得了。
#include <cstdio>
#include <cstring>
#define int long long
const int p = 1000000007;
int T, x, m, f[200005][10];
int get(int x) {
if(x < 0) return 1;
int an = 0;
for(int i = 0; i <= 9; i++) an = (an + f[x][i]) % p;
return an;
}
signed main() {
scanf("%lld", &T);
f[0][1] = f[0][0] = 1;
for(int i = 1; i <= 200000; i++) {
for(int j = 9; j >= 1; j--) f[i][j] = f[i-1][j-1];
f[i][0] = 0;
f[i][0] = (f[i][0] + f[i-1][9]) % p;
f[i][1] = (f[i][1] + f[i-1][9]) % p;
}
while(T--) {
scanf("%lld%lld", &x, &m);
int ans = 0;
while(x) {
int d = x % 10;
ans = (ans + get(m - (10-d))) % p;
x /= 10;
}
printf("%lld\n", ans);
}
return 0;
}
本想着上 expert, 结果卡在 ! 太让我失望了,要是看清题目,那 分不扣说不定就上蓝了。