Make Equal With Mod
思路:这是一道思维题,我们贪心来看,一定是从最大的开始操作,最大的和自己取模不会影响其他数,但是如果既有零也有一定不行,所以只要没有一,肯定可以操作完成,有一的话就只能全部变为一,那么就从最大的开始和比自己小一的数取模,然后比自己小一的数存在,那也一定不行
void solve() {
int n; cin >> n;
map<int, int> mp;
vector<int> a(n + 1);
for (int i = 1; i <= n; i ++) {
cin >> a[i];
mp[a[i]] ++;
}
if (mp.size() == 1) {
cout << "YES" << '\n';
return ;
}
if (mp.count(1)) {
if (mp.count(0)) {
cout << "NO" << '\n';
return ;
}
for (int i = 1; i <= n; i ++) {
if (a[i] <= 1) continue;
if (mp.count(a[i] - 1)) {
cout << "NO" << '\n';
return ;
}
}
cout << "YES" << '\n';
} else cout << "YES" << '\n';
}
Game on Ranges
思路:所有数据保证不超过 1000 1000 1000,直接 n 2 n^2 n2暴力就行,区间从小到大
void solve() {
int n; cin >> n;
vector<array<int, 2>> seg, t;
for (int i = 0; i < n; i ++) {
int l, r; cin >> l >> r;
seg.push_back({l, r});
}
t = seg;
map<int, int> mp;
sort(seg.begin(), seg.end(), [&](array<int, 2> a, array<int, 2> b) {
return a[1] - a[0] < b[1] - b[0];
});
map<array<int, 2>, int> ans;
for (auto [l, r] : seg) {
for (int i = l; i <= r; i ++) {
if (!mp.count(i)) {
mp[i] ++;
ans[ {l, r}] = i;
break;
}
}
}
for (auto [l, r] : t) {
cout << l << ' ' << r << ' ';
cout << ans[ {l, r}] << '\n';
}
cout << '\n';
}
Buy an Integer
思路:枚举 d ( N ) d(N) d(N)的值,二分 N N N即可
int get(int x) {
int cnt = 0;
while (x) {
cnt ++;
x /= 10;
}
return cnt;
}
void solve() {
int a, b, x; cin >> a >> b >> x;
int ans = 0;
int p = 1;
for (int i = 1; i <= 10; i ++) {
if (i >= 2) p *= 10;
int y = x - b * i;
int l = p, r = 1e9, res = -1;
while (l <= r) {
int mid = l + r >> 1;
if (get(mid) == i && a * mid + b * i <= x) l = mid + 1, res = mid;
else r = mid - 1;
}
ans = max(ans, res);
}
cout << ans << '\n';
}
String Formation
思路:用两个数组模拟来维护加在两边的字符就行行
void solve() {
string s; cin >> s;
int Q; cin >> Q;
vector<char> f, b;
int t = 1;
while (Q --) {
int op; cin >> op;
if (op == 1) {
t ^= 1;
} else {
int x; char c; cin >> x >> c;
if (t == 1) {
if (x == 1) f.push_back(c);
else b.push_back(c);
} else {
if (x == 1) b.push_back(c);
else f.push_back(c);
}
}
}
if (t == 1) {
reverse(f.begin(), f.end());
for (auto i : f) cout << i;
for (auto i : s) cout << i;
for (auto i : b) cout << i;
} else {
reverse(b.begin(), b.end());
for (auto i : b) cout << i;
reverse(s.begin(), s.end());
for (auto i : s) cout << i;
for (auto i : f) cout << i;
}
}
Bouquet
思路:组合数的题,那总的方案数减去选 a a a和选 b b b的方案数就是答案,因为保证 a a a, b b b不超过 2 e 5 2e5 2e5,所以计算 C ( n , a ) C(n, a) C(n,a)和 C ( n , b ) C(n, b) C(n,b)的时候化简一下公式就行,不知道为什么 l u c a s lucas lucas也可以过
int ksm(int a, int k) {
int res = 1;
while (k) {
if (k & 1) res = (res * a) % mod;
a = (a * a) % mod;
k >>= 1;
}
return res;
}
int C(int a, int b) {
int ans = 1, inv = 1;
for (int i = 1; i <= b; i ++) {
inv = inv * ksm(i, mod - 2) % mod;
}
for (int i = a - b + 1; i <= a; i ++) {
ans = ans * i % mod;
}
return ans * inv % mod;
}
void solve() {
int a, b, n; cin >> n >> a >> b;
cout << (((ksm(2, n) - C(n, a) + mod) % mod - C(n, b) + mod) % mod - 1 + mod) % mod << '\n';
}
Permutation
思路:一个不那么典型的状压 d p dp dp, d p [ i ] dp[i] dp[i]表示选择数的情况为 i i i的时候的方案数(用一个数字的二进制表示, 0 0 0表示不选这个数, 1 1 1表示选这个数),从选 1 1 1个数一直转移到选 n n n个数,在转移的过程中我们要判断选出来的数是不是符合选这些数量的数的限制条件,符合条件在进行转移,这里的dp[i ^ (1 << (j - 1))] 不选 j j j这个数的方案数
void solve() {
int n, m; cin >> n >> m;
map<int, vector<array<int, 2>>> mp;
for (int i = 1; i <= m; i ++) {
int x, y, z; cin >> x >> y >> z;
mp[x].push_back({y, z});
}
vector<int> dp(1 << n);
dp[0] = 1;
for (int i = 1; i < 1 << n; i ++) {
vector<int> t;
int cv = 0, ok = 0;
for (int j = 0; j < n; j ++) {
if (i >> j & 1) t.push_back(j + 1), cv ++;
}
for (auto [y, z] : mp[cv]) {
int cnt = 0;
for (auto j : t) {
if (j <= y) cnt ++;
if (cnt > z) ok = 1;
}
}
if (!ok) {
for (auto j : t) {
dp[i] += dp[i ^ (1 << j - 1)];
}
}
}
cout << dp[(1 << n) - 1] << '\n';
}
String Cards
思路:字符串连接起来最小,首先想到自定义排序,但是这样还远远不行,排个序就能过的这个题是选全部的字符串,而这个题是选 k k k个字符串,所以 d p dp dp,设 d p [ i ] [ j ] dp[i][j] dp[i][j]表示在 i − n i-n i−n这个区间里面选 j j j个字符串行成最小字典序的字符串,这个题有后效性的影响,所以我们倒着往前 d p dp dp
从前往后为什么不对的样例
输入
4 3
bababa
bab
b
b
输出
bababababb
void solve() {
int n, k; cin >> n >> k;
vector<string> s(n + 1);
for (int i = 1; i <= n; i ++) {
cin >> s[i];
}
sort(s.begin() + 1, s.end(), [&](string a, string b) {
return a + b < b + a;
});
vector<vector<string>> dp(n + 2, vector<string>(n + 2));
dp[n][1] = s[n];
for (int i = n - 1; i >= 1; i --) {
for (int j = 1; j <= n - i + 1; j ++) {
dp[i][j] = s[i] + dp[i + 1][j - 1];
if (dp[i + 1][j] != "") dp[i][j] = min(dp[i + 1][j], dp[i][j]);
}
}
cout << dp[1][k] << '\n';
}