唉最近状态越来越差。。。
A. GukiZ and Contest
给你n个人的分数然后输出排名。
一遍排序搞定。
#include <bits/stdc++.h>
using namespace std;
struct Node{
int val, pos;
bool operator < (const Node &n) const {
return val > n.val;
}
};
int n;
Node arr[2005];
map<int, int> vis;
int ans[2005];
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> arr[i].val;
arr[i].pos = i;
}
sort(arr + 1, arr + n + 1);
int tot = 0;
for (int i = 1; i <= n; i++) {
int t = arr[i].val;
if (vis[t]) {
ans[arr[i].pos] = vis[t];
tot++;
}
else {
vis[t] = ++tot;
ans[arr[i].pos] = tot;
}
}
for (int i = 1; i <= n; i++)
cout << ans[i] << " \n"[i == n];
return 0;
}
B. ZgukistringZ
3个串a,b,c,可以将a任意重组,要求重组之后包含的无重叠部分
的b串和c串的个数最多,问个数最多是多少。
计算a串26个字母分别出现了多少次,然后枚举b串的个数,计算最多能放多少c串。
#include <bits/stdc++.h>
using namespace std;
char a[100005], b[100005], c[100005];
int cnta[30];
int cntb[30];
int cntc[30];
int temp[30];
int main() {
cin >> a >> b >> c;
int lena = strlen(a);
int lenb = strlen(b);
int lenc = strlen(c);
for (int i = 0; i < lena; i++) {
char c = a[i];
cnta[c - 'a']++;
temp[c - 'a']++;
}
for (int i = 0; i < lenb; i++) {
cntb[b[i] - 'a']++;
}
for (int i = 0; i < lenc; i++) {
cntc[c[i] - 'a']++;
}
int mx = 0;
int mxi = 0, mxj = 0;
for (int i = 0; i < lena; i++) {
int cc = 0x3f3f3f3f;
for (int j = 0; j < 26; j++) {
if (!cntc[j]) continue;
int t = cnta[j] / cntc[j];
cc = min(cc, t);
}
if (i + cc > mx) {
mxi = i;
mxj = cc;
mx = i + cc;
}
bool flag = false;
for (int k = 0; k < 26; k++) {
cnta[k] -= cntb[k];
if (cnta[k] < 0) {
flag = true;
break;
}
}
if (flag) break;
}
for (int i = 0; i < mxi; i++) {
printf("%s", b);
}
for (int i = 0; i < mxj; i++) {
printf("%s", c);
}
for (int i = 0; i < 26; i++) {
for (int j = 0; j < temp[i] - mxi * cntb[i] - mxj * cntc[i]; j++)
printf("%c", 'a' + i);
}
cout << endl;
return 0;
}
C. GukiZ hates Boxes
n堆货物摆成一排,有m个人,所有人一开始在所有货物的左边。
每一分钟每个人可以有两种选择:
向右走一格。
把他当前所在位置的货物搬走一个。
问把所有货物都搬走最少需要多少分钟。
二分答案,判断能否在一定时间内搬完所有货物,过程如下:
对于每一个人,先让他走到最后一个有货物的位置,然后剩余的时间全部用来搬货物,先搬最后一堆,如果还有时间就搬倒数第二堆(依次类推)。注意他剩了多少时间一定能搬多少货物,因为在走到最后的过程中,可以随时花费一分钟用来搬货物。
#include <bits/stdc++.h>
using namespace std;
int n;
long long m;
long long arr[100005];
long long temp[100005];
bool solve(long long mid) {
for (int i = 1; i <= n; i++)
temp[i] = arr[i];
int pos = n;
long long tot = 0;
while (pos > 0) {
while (!temp[pos] && pos) pos--;
tot++;
long long tim = mid - pos;
if (tim <= 0 && temp[pos]) return false;
while (tim >= temp[pos] && pos) {
tim -= temp[pos];
temp[pos--] = 0;
}
temp[pos] -= tim;
if (tot > m) return false;
}
return tot <= m;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> arr[i];
}
long long l = 0, r = 2000000000000000;
while (l < r) {
long long mid = l + r >> 1;
if (solve(mid)) r = mid;
else l = mid + 1;
}
cout << l << endl;
return 0;
}
D. GukiZ and Binary Operations
问有多少个长度为n的数组a,数组中的每个元素严格小于 2l ,满足 (a1&a2)|(a2&a3)|...|(an−1&an)=k?
输出方案数模m。
太神了我一点也不会。
我们枚举k的每一位,方案数就是每一位的方案数的乘积。
如果这一位是0,则说明数组一定没有连续两个元素是1。设 dp[i] 表示到第i位的方案数,很显然 dp[i]=dp[i−1]+dp[i−2] ,用矩阵计算。
如果这一位是1,则说明数组中至少有一个两个连续的1,呃。。。不就是 2n−dp[n] 么。
好了完了。
#include <bits/stdc++.h>
using namespace std;
long long n, k, l, m;
struct matrix{
int n, m;
long long arr[2][2];
matrix(int a, int b) {
n = a, m = b;
memset(arr, 0, sizeof(arr));
}
};
matrix operator * (matrix a, matrix b) {
matrix c(a.n, b.m);
for (int i = 0; i < a.n; i++) {
for (int j = 0; j < b.m; j++) {
for (int p = 0; p < a.m; p++) {
long long t = a.arr[i][p] * b.arr[p][j] % m;
c.arr[i][j] += t;
c.arr[i][j] %= m;
}
}
}
return c;
}
matrix pow(matrix a, long long b) {
matrix c(2, 2);
c.arr[0][0] = c.arr[1][1] = 1;
while (b) {
if (b & 1) c = c * a;
a = a * a;
b >>= 1;
}
return c;
}
bool judge() {
long long t = k;
for (int i = 0; i < l; i++) t >>= 1;
return t == 0;
}
long long DP() {
matrix ans(1, 2);
ans.arr[0][0] = ans.arr[0][1] = 1;
matrix base(2, 2);
base.arr[0][1] = base.arr[1][0] = base.arr[1][1] = 1;
base = pow(base, n);
ans = ans * base;
return ans.arr[0][1];
}
long long power(long long a, long long b) {
long long ans = 1;
while (b) {
if (b & 1)
ans = ans * a % m;
a = a * a % m;
b >>= 1;
}
return ans;
}
int main() {
cin >> n >> k >> l >> m;
if (!judge()) {
cout << 0 << endl;
return 0;
}
long long ans = 1;
long long a = DP();
long long b = (power(2ll, n) - a + m) % m;
for (int i = 0; i < l; i++) {
if ((k >> i) & 1)
ans = ans * b % m;
else ans = ans * a % m;
}
cout << ans % m << endl;
return 0;
}
E. GukiZ and GukiZiana
一个长度为n的序列,要求维护两种操作:
1 l r x. 把[l, r]中的所有数加上x。
2 y. 询问j - i的最大值使a[i] = a[j] = y。
分块。
把数组分成 n√ 块,每块 n√ 个数,然后对每一块排序。
对于操作1,如果[l, r]覆盖了某一块,则给这一块加上一个标记。
如果[l, r]覆盖了某一块的一部分则暴力加上x。
对于操作2,枚举每一块用lower_bound查找值。
第一次写分块,如何装作经常写的样子?写的不好见谅。
#include <bits/stdc++.h>
#define pli pair<long long, int>
#define mp(i, j) make_pair(i, j)
using namespace std;
const int MAXN = 500005;
int n, q;
long long arr[MAXN];
int blocks;
long long tag[MAXN];
vector<pli > mi[770], mx[770];
void rebuild(int id) {
mi[id].clear();
mx[id].clear();
for (int i = id * blocks; i < (id + 1) * blocks && i < n; i++) {
arr[i] += tag[id];
mi[id].push_back(mp(arr[i], i));
mx[id].push_back(mp(arr[i], -i));
}
sort(mi[id].begin(), mi[id].end());
sort(mx[id].begin(), mx[id].end());
tag[id] = 0;
}
int getmin(long long v) {
for (int i = 0; i < blocks; i++) {
long long t = v - tag[i];
vector<pli >::iterator it = lower_bound(mi[i].begin(), mi[i].end(), mp(t, 0));
if (it != mi[i].end() && (it -> first == t)) return it -> second;
}
return -1;
}
int getmax(long long v) {
for (int i = blocks - 1; i >= 0; i--) {
long long t = v - tag[i];
vector<pli >::iterator it = lower_bound(mx[i].begin(), mx[i].end(), mp(t, -10000000));
if (it != mx[i].end() && (it -> first == t)) return -it -> second;
}
return -1;
}
int main() {
cin >> n >> q;
blocks = sqrt(n) + 2;
for (int i = 0; i < n; i++)
cin >> arr[i];
for (int i = 0; i < blocks; i++)
rebuild(i);
int op, l, r;
long long v;
for (int i = 0; i < q; i++) {
cin >> op;
if (op == 1) {
cin >> l >> r >> v;
l--, r--;
if (l / blocks == r / blocks) {
for (int j = l; j <= r; j++)
arr[j] += v;
rebuild(l / blocks);
} else {
int id = l / blocks + 1;
while (l / blocks != id) {
arr[l++] += v;
}
rebuild(l / blocks - 1);
while (l + blocks < r) {
tag[l / blocks] += v, l += blocks;
}
while (l <= r) arr[l++] += v;
rebuild(r / blocks);
}
} else {
cin >> v;
l = getmin(v);
r = getmax(v);
if (l < 0) cout << -1 << endl;
else cout << r - l << endl;
}
}
return 0;
}