文章目录
感想
2/7,笑嘻了,D题忘了一个情况结果后面被卡了,排名直接翻一番,一看周围都是被卡了的哥们。1100的通过直接变600。
C题疑似找规律题,但我不是很懂原理,没写出来,场下照着样例编了一个过的,有个牛人写了个(i >> 32) + j也过了,完全不懂原理。
A. Likes
1.题目内容
2.个人思路:
照着题目思路来就行,最大就先正数再负数,最小就正数负数轮换再全放正数。
3.代码:
ll t, m, n, p = 998244353;
ll mix[105];
int main() {
cin >> t;
while (t--) {
cin >> n;
int ma = 0;
for (int i = 1; i <= n; i++) {
cin >> mix[i];
if (mix[i] > 0) ma++;
}
int mi = n - ma, tmp = mi;
for (int i = 1; i <= n; i++) {
if (i > ma) ma--;
cout << (i > ma ? ma : i) << " ";
}
cout << "\n";
int la = 0;
for (int i = 1; i <= n; i++) {
if (i <= mi * 2) {
if (i % 2) cout << 1 << " ";
else cout << 0 << " ";
la = i % 2;
}
else {
la++;
cout << la << " ";
}
}
cout << "\n";
}
return 0;
}
B. Settlement of Guinea Pigs
1.题目内容
2.个人思路:
还是找规律模拟,在两次遇到医生之间的所有都需要再弄一个鸟笼,遇到医生后就考虑已知性别最坏情况,就是 当前总数/2 + 1,
奇数情况:一定是这个结果,证明省略。
偶数情况:最坏两个性别的笼子内都有奇数个,此时就额外需要一个笼子,所以也是 当前总数/2 + 1。
3.代码:
ll t, m, n, p = 998244353;
ll arr[100005];
int main() {
cin >> t;
while (t--) {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> arr[i];
}
int sum = 0, now = 0, res = 0;
int tot = 0;
for (int i = 1; i <= n; i++) {
if (arr[i] == 1) {
sum++;
now++;
tot++;
}
else {
if(tot % 2 == 0 && tot > 0) now = tot / 2 + tot % 2 + 1;
else now = tot / 2 + tot % 2;
}
res = max(res, now);
}
cout << res << "\n";
}
return 0;
}
C. The Very Beautiful Blanket
1.题目内容
2.个人思路:
没有思路,完全不懂,场上也没做出来,代码是我照葫芦画瓢弄得,看个乐呵吧。
3.代码:
ll t, m, n, p = 998244353;
ll mir[305][305];
int main() {
cin >> t;
while (t--) {
cin >> n >> m;
int now = 0;
for (int i = 1; i <= n; i += 2) {
now = 512 * (i / 2);
for (int j = 1; j * 2 <= m + 1; j++) {
mir[i][j * 2 - 1] = now++;
mir[i][j * 2] = now++;
mir[i + 1][j * 2 - 1] = now++;
mir[i + 1][j * 2] = now++;
}
}
cout << n * m << "\n";
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cout << mir[i][j] << " ";
}
cout << "\n";
}
}
return 0;
}
D. Buying gifts
1.题目内容
2.个人思路:
比较好想的dp题,但是有点细枝末节的地方容易遗忘。
先对a进行排序,然后记录b从后到前的最大值,接下来考虑a位于第i个下的情况。假设dp[i]为a中最贵物品为a[i]时的最小差。
此时,b[i](跟着a排序变换过的)前的数字可以任取(包括不取!),另外b[i + 1] ~ b[n]的所有数字是必须取的,所以设max[i + 1] 为 b[i + 1] ~ b[n]的最大值,则在取i之前的数字的情况下:
dp[i] = min(dp[i], abs(a[i] - max(max[i + 1], 1~i - 1中最接近a[i]的)))
如果不取,情况则为:
dp[i] = min(dp[i], abs(a[i] - max[i + 1]))。
至于找最接近的,使用set即可。
这个题关键是考虑没拿b中前边数字的情况,很容易忘记,pretest也没提这茬,然后就挂了。
3.代码:
struct com {
ll f;
ll to;
bool operator < (const com& b) const {
if (f == b.f) return to > b.to;
return f < b.f;
}
}crr[500005];
ll t, m, n, p = 998244353;
ll dp[500005], mm[500005];
set<ll> useb;
int main() {
cin >> t;
while (t--) {
cin >> n;
ll ans = 2147483647ll;
useb.clear();
for (int i = 1; i <= n; i++) {
ll a, b;
cin >> a >> b;
crr[i] = { a, b };
}
mm[n + 1] = 0;
sort(crr + 1, crr + 1 + n);
for (int i = n; i > 0; i--) {
mm[i] = max(crr[i].to, mm[i + 1]);
}
useb.insert(crr[1].to);
ans = abs(crr[1].f - mm[2]);
for (int i = 2; i <= n; i++) {
dp[i] = 2147483647ll;
auto x = useb.lower_bound(crr[i].f);
if (x != useb.end()) {
if (mm[i + 1] >= *x) {
dp[i] = min(dp[i], abs(crr[i].f - mm[i + 1]));
}
else {
dp[i] = min(dp[i], abs(crr[i].f - *x));
}
}
if (x != useb.begin()) {
x--;
if (mm[i + 1] >= *x) {
dp[i] = min(dp[i], abs(crr[i].f - mm[i + 1]));
}
else {
dp[i] = min(dp[i], abs(crr[i].f - *x));
}
}
if(i != n)
dp[i] = min(dp[i], abs(crr[i].f - mm[i + 1]));
ans = min(ans, dp[i]);
useb.insert(crr[i].to);
}
cout << ans << "\n";
}
return 0;
}
E. Music Festival
1.题目内容
2.个人思路:
考虑将每一张唱片按照最大值从小到大排序,之所以这么做,是因为在加入了最大值为x的唱片后,所有小于x的唱片全部无效,所以最佳策略一定从这里诞生。
还是考虑dp,遍历每一个唱片的每一个曲子的coooool值,以及这张唱片所能贡献的unit of impression,显而易见,这个数字取决于之前序列的最大值,
即第i个位置为 dp[i] = max( dp[j](j < i) + 序列中大于第j个位置所单调递增的序列长度)。
乍一看这个思路需要O(n^2)以上才能处理,但我们可以换一个角度,即每次完成一个唱片后,记录下当前唱片最大值和最大值对应的长度,然后遍历新的唱片曲子,这个时候,我们通过map查询小于当前唱片歌曲值的所保存的长度,再加上从当前位置到最大值的上升序列长度即为所求。
只需要O(nlogn)的时间即可处理,本题需要读入优化,cin会爆。
3.代码:
struct com {
ll f;
ll to;
ll s;
bool operator < (const com& b) const {
if (f == b.f) return to > b.to;
return f < b.f;
}
}lis[200005];
ll t, m, n, p = 998244353;
ll dp[200005];
map<ll, ll> lim;
vector<ll> alb[200005];
//ll tr[2000005], lz[2000005];
int main() {
cin >> t;
while (t--) {
cin >> n;
int ans = 0;
lim.clear();
for (int i = 1; i <= n; i++) {
alb[i].clear();
dp[i] = 0;
int k;
scanf_s("%d", &k);
int f = 0, l = 0;
for (int j = 0; j < k; j++) {
int a;
scanf_s("%d", &a);
if (a > f) {
f = a;
l++;
}
alb[i].push_back(a);
}
lis[i] = { f, l, i };
}
sort(lis + 1, lis + 1 + n);
int now = 0;
lim.insert({ 0, 0 });
for (int i = 1; i <= n; i++) {
int tmp = alb[lis[i].s].size(), x = lis[i].s;
int nm = 0, ns = 0;
for (int j = 0; j < tmp; j++) {
int y = alb[x][j];
if (y > nm) {
nm = y;
auto z = lim.lower_bound(y);
z--;
dp[i] = max(dp[i], z->second + lis[i].to - ns);
ns++;
}
}
dp[i] = max(dp[i], dp[i - 1]);
lim.insert({ lis[i].f, dp[i] });
}
cout << dp[n] << "\n";
}
return 0;
}
总结
笑嘻了,真的蚌埠住了,C题半天也没想明白,希望有大佬能解释一下吧,我对这个思路只能说神奇。