A.Two Regular Polygons
题意:
给定t组数据,每组给定一个正n边形和正m边形(m<n),询问是否能在正n边形中找到正m边形,即两个正多边形的顶点是否能完全重合。
题解:
因为n>m,只要判断n%m是否为0即可
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; const int maxn = 5e5 + 5; const int INF = 0x3f3f3f3f; const int mod = 998244353; void solve() { int n, m; scanf("%d%d", &n, &m); if (n % m == 0) puts("YES"); else puts("NO"); } int main() { int t; for (scanf("%d", &t); t >= 1; t--) solve(); }
B.Bogosort
题意:
给一组数组,要求排序,使得任意i,j,i-a[i]!=j-a[j]
题解:
将数组从大到小排序就能满足条件
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; const int maxn = 5e5 + 5; const int INF = 0x3f3f3f3f; const int mod = 998244353; int a[105]; void solve() { int n; scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%d", &a[i]); sort(a, a + n, greater<int>()); for (int i = 0; i < n; i++) printf("%d ", a[i]); puts(""); } int main() { int t; for (scanf("%d", &t); t >= 1; t--) solve(); }
C.Adding Powers
题意:
给定一个n个元素的数组,要求判断是否能由一个全为0的数组,加上k的i次(i=1,2,3,4…)相加得到,并且i不能重复
题解:
把每个数拆成k 进制。依题意,每一位至多是1,否则就不行
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; const int maxn = 5e5 + 5; const int INF = 0x3f3f3f3f; const int mod = 998244353; int add[70]; void solve() { memset(add, 0, sizeof(add)); int n, k; scanf("%d%d", &n, &k); int f = 0; for (int i = 0; i < n; i++) { ll x; scanf("%lld", &x); int j = 0; while (x) { add[j] += (x % k); if (add[j] > 1) { f = 1; break; } x /= k; j++; } } if (f) puts("NO"); else puts("YES"); } int main() { int t; for (scanf("%d", &t); t >= 1; t--) solve(); }
D.Count the Arrays
题意:
构造一个长度为n的数组,值的范围1~m的数组,满足下面条件
1.数组中只能且必须出现一对相同的数字
2.先递增再递减
输出所有的构造方案数量
题解:
有且只有两个数相等,所以每个数组有n-1的数,从m中取n-1个数有C(m,n-1)种,只要将最大的数放在中间剩余的n-2个数只要分成两组放在两边即可,每个数都能放在左右两边,为了防止出现数全在一边的情况可以每次取出一个数放在右边,如果剩下的数全出现在左边也满足条件,因为有对称性所以成立,总共为。所以最终答案为
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; const int maxn = 2e5 + 5; const int INF = 0x3f3f3f3f; const int mod = 998244353; ll fac[maxn]; ll qpow(ll a, ll b) { int res = 1; while (b) { if (b & 1) res = res * a % mod; a = a * a % mod; b >>= 1; } return res; } void init() { fac[0] = 1; for (int i = 1; i < maxn; i++) fac[i] = fac[i - 1] * i % mod; } ll c(int x, int y) { return fac[x] * qpow(fac[y] * fac[x - y] % mod, mod - 2) % mod; } int main() { init(); int n, m; scanf("%d%d", &n, &m); if (n == 2) { puts("0"); return 0; } printf("%lld\n", ((c(m, n - 1) * qpow(2, n - 3)) % mod * 1ll * (n - 2)) % mod); return 0; }
E.Array Shrinking(DP)
题意:
给定一组长度为n的序列,每次可以将相邻的两个相等元素,即ai==a(i+1) ,合并成一个新的元素,其值为 ,询问经过多次操作后数组最小长度
题解:
首先可以 的预处理出所有可以合并的情况用,a[i][j]表示原先数组的[i,j]的数最终会合并成的数的值。dp[i]表示[1~i]中最多能合并的数个数,所以最终答案就是n-dp[n]。
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; const int maxn = 505; const int INF = 0x3f3f3f3f; const int mod = 998244353; int n, a[maxn][maxn], dp[maxn]; int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i][i]); for (int i = n; i; i--) for (int j = i + 1; j <= n; j++) for (int k = i; k < j; k++) if (a[i][k] && a[i][k] == a[k + 1][j]) a[i][j] = a[i][k] + 1; for (int i = 1; i <= n; i++) for (int j = 1; j <= i; j++) if (a[j][i]) dp[i] = max(dp[i], dp[j - 1] + i - j); cout << n - dp[n]; }