A. Array and Peaks
题目大意
询问是否存在一个长度为 n 的排列有 k 个波峰(同时满足 ai > ai-1 和 ai > ai+1 的 i 就是一个波峰)
思路
考虑一个长度为 n 的排列存在最多波峰的情况,即:1、n、2、n-1、3、n-2 …
可以发现,最多波峰数等于 (n-1) / 2 向下取整。
每次询问,如果 k <= (n-1) / 2 向下取整,那么我们依次输出 k 个波峰以后,在顺序输出剩下的数即可。
AC代码
#include <bits/stdc++.h>
#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#define ll long long
#define chushi(a, b) memset(a, b, sizeof(a))
#define endl "\n"
const double eps = 1e-8;
const ll INF = 9223372036854775807;
const int mod = 1e9+7;
const int maxn = 2e5 + 5;
using namespace std;
int main(){
int ncase;
cin >> ncase;
while(ncase--){
int n, k;
cin >> n >> k;
if(k > (n-1)/2) cout << "-1" << endl;
else{
cout << 1 << " ";
for(int i = 1; i <= k; i++) cout << n+1-i << " " << i+1 << " ";
for(int i = 1+k+1; i <= n-k; i++) cout << i << " ";
cout << endl;
}
}
return 0;
}
B. AND Sequences
题目大意
给出一个有 n 个元素的数组 a,求:对于所有的 i ,都满足 a1 & a2 & … & ai = ai+1 & ai+2 &…& an 的排列的个数
思路
观察题目要求:
当 i = 1 时,有 a1 = a2 & a3 & a4 & a5 & … &an-1 & an
当 i = n 时,有 a1 & a2 & a3 & a4 & a5 & … &an-1 = an
由上我们可以确定,对于一个满足的排列方式一定有 a1 = an
对于 & 运算的特点,1 & 1 = 1,其他情况均为 0。
也就是说,我们对 n 个数进行连续的 & 运算的结果 tmp 应该放在 a1 或者 an 的位置。
所以说,如果数字 a 中有 cnt 个数等于 tmp ,当 cnt >= 2 and 对于所有的 ai & tmp == tmp 时,这个数组才满足题意的排列,排列的总数为: cnt * (cnt-1) * ((n-2)!)
AC代码
#include <bits/stdc++.h>
#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#define ll long long
#define chushi(a, b) memset(a, b, sizeof(a))
#define endl "\n"
const double eps = 1e-8;
const ll INF = 9223372036854775807;
const ll mod = 1e9+7;
const int maxn = 2e5 + 5;
using namespace std;
ll a[maxn];
int main(){
int ncase;
cin >> ncase;
while(ncase--){
ll n;
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
ll tmp = a[1];
for(int i = 2; i <= n; i++) tmp &= a[i];
ll f = 1, cnt = 0;
for(int i = 1; i <= n; i++){
if((a[i] & tmp) != tmp) f = 0;
if(a[i] == tmp) cnt++;
}
if(f == 0 || cnt < 2){
cout << 0 << endl;
continue;
}
ll res = 0;
res = cnt * (cnt-1) % mod;
for(ll i = 1; i <= n-2; i++) res = res * i % mod;
cout << res << endl;
}
return 0;
}
C. Add One
题目大意
给出一个数 n,对它进行 d 次操作,求出操作过后这个数的长度。
这个操作为:对于一个数 x,对 x 的每个数位都 +1。eg:5 -> 6, 123 -> 234, 129 -> 2310。
思路
我们先预处理对 0 进行 z 次操作后得到的数的长度, 再预处理对 0 进行 d 次操作后得到的数的长度。
我们把一个数 num 拆开来看,对于一个数位 x 来说,它需要 10 - x 次操作变成 10。
如果 10 - x 大于 d ,则 d 次操作不好让改变长度。
如果 10 - x 小于等于 d,也就是说可以对 10 进行 d - (10-x) 次操作,也就是说分别对 0 和 1 进行 d - (10-x) 次操作。
对所有数位进行这样的计算即可。
AC代码
#include <bits/stdc++.h>
#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#define ll long long
#define chushi(a, b) memset(a, b, sizeof(a))
#define endl "\n"
const double eps = 1e-8;
const ll INF = 9223372036854775807;
const ll mod = 1e9+7;
const int maxn = 2e5 + 5;
using namespace std;
ll v[2][maxn] = {0};
ll sum[maxn] = {0};
template<class T>inline void read(T &res)
{
char c;T flag=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}
void init() {
for(int i = 0; i < 10; i++) v[0][i] = 1;
for(int i = 0; i < 9; i++) v[1][i] = 1;
v[1][9] = 2;
for(int i = 10; i < maxn; i++) {
v[0][i] = (v[0][i - 10] % mod + v[1][i - 10] % mod) % mod;
v[1][i] = (v[0][i - 9] % mod + v[1][i - 9] % mod) % mod;
}
for(int i = 0; i < maxn; i++) sum[i] = (v[0][i] + v[1][i]) % mod;
}
int main(){
init();
int ncase;
read(ncase);
while(ncase--){
ll n, m;
read(n); read(m);
ll res = 0;
while(n){
ll tmp = 10 - (n % 10);
if(m < tmp) res++;
else{
res += sum[m - tmp];
res %= mod;
}
n /= 10;
}
printf("%lld\n", res);
}
return 0;
}
D. GCD and MST
思路
这是一个披着图论的皮的思维题,按照题意去找,对于每个点都选择花费最小的连接方式即可。
AC代码
#include <iostream>
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 2e5 + 5;
ll a[maxn];
bool f[maxn] = {false};
vector<pair<ll, int> > v;
int main(int argc, char** argv) {
int ncase;
cin >> ncase;
while(ncase--){
ll n, p;
cin >> n >> p;
for(int i = 1; i <= n; i++) cin >> a[i];
pair<ll, int> tmp;
for(int i = 1; i <= n; i++){
tmp.second = i;
tmp.first = a[i];
v.push_back(tmp);
}
sort(v.begin(), v.end());
ll res = n * p - p;
for(int i = 0; i < n; i++){
if(v[i].first >= p) break;
if(f[v[i].second]) continue;
int ind = v[i].second;
for(int j = ind-1; j > 0; j--){
if(a[j] % a[ind] != 0) break;
res = res - p + a[ind];
if(f[j]) break;
f[j] = true;
}
for(int j = ind+1; j <= n; j++){
if(a[j] % a[ind] != 0) break;
res = res - p + a[ind];
if(f[j]) break;
f[j] = true;
}
f[ind] = true;
}
cout << res << endl;
for(int i = 1; i <= n; i++) f[i] = false;
v.clear();
}
return 0;
}