A. Tales of a Sort
题意:
给定一个长度为n的数组,你可以进行以下操作:对于所有的i,ai=max(ai-1,0)。问最少进行几次操作使得数组非降序。
题解:
#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 1e6 + 10, MOD = 998244353, INF = 0x3f3f3f3f;
int a[N];
void solve()
{
int n, ans = 0;
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
for (int i = n - 1; i >= 1; --i)
{
if (a[i] > a[i + 1])
ans = max(ans, a[i]);
}
printf("%d\n", ans);
}
int main()
{
int T = 1;
scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
B. Good Arrays
题意:
给出一个正整数数组a,问是否能够构造一个正整数数组b,使得ai!=bi&&。
题解:
ai=1的情况bi至少要为2,考虑对于所有ai=1时使得bi=2之后剩下的值是否还够至少每个位置放一个1,设,sum-cnt1>=n即可。特别的当n=1的情况也无法构造。
#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 1e5 + 10, MOD = 998244353, INF = 0x3f3f3f3f;
int a[N];
void solve()
{
int n;
LL sum=0,cnt1=0;
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
scanf("%d", &a[i]);
sum += a[i];
if (a[i] == 1)++cnt1;
}
if (n == 1)
{
printf("NO\n");
return;
}
if (sum - cnt1 >= n)
printf("YES\n");
else
printf("NO\n");
}
int main()
{
int T = 1;
scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
C. To Become Max
题意:
给出一个长度为n的数组,你可以进行以下操作:选择一个下标i(1<=i<=n-1,ai<=ai-1),使ai加一。问经过至多k次操作之后数组的最大值最大为多少。
题解:
二分答案,对于每个位置判断一下是否能够堆到即可。
#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 1e3 + 10, MOD = 998244353, INF = 0x3f3f3f3f;
int n, k, a[N];
LL get_step(int x, int i)
{
LL s = 0;
while (i <= n)
{
if (a[i] >= x)
return s;
s += x - a[i];
--x;
++i;
}
return 1e9;
}
bool check(int x)
{
for (int i = 1; i < n; ++i)
{
if (get_step(x, i) <= k)
return 1;
}
return 0;
}
void solve()
{
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
int l = a[n], r = 1e9;
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid))
l = mid;
else
r = mid - 1;
}
printf("%d\n", l);
}
int main()
{
int T = 1;
scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
D. More Wrong
题意:
交互题。有一个隐藏的长度为n的排列a,你可以进行以下询问:? l r 花费(r-l)^2的代价询问l到r区间的逆序对的数量。你需要在5*n^2点代价的限制内找出排列的最大值,并输出! max_idx。
题解:
分治。当我们已知x是左半段区间最大值的下标,y是右半段区间最大值的下标时,我们可以用以下的方法判断ax与ay哪个大:询问? l r-1的逆序对数量f1,? l r的逆序对数量f2,如果f1==f2说明逆序对数量没有增加,即ay>ax。基本思路就这样然后加点细节..
赛时先输出!再进dfs给我一直wa,太若至了。
#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 5e3 + 10, MOD = 998244353, INF = 0x3f3f3f3f;
int cmp(int l, int r)
{
if (l + 1 == r)
{
cout << "? " << l << " " << r << endl;
int f;
cin >> f;
if (f)return l;
return r;
}
LL f1, f2;
cout << "? " << l << " " << r - 1 << endl;
cin >> f1;
cout << "? " << l << " " << r << endl;
cin >> f2;
if (f1 == f2)
return r;
return l;
}
int dfs(int l, int r)
{
if (l == r)return l;
if (l + 1 == r)return cmp(l, r);
int mid = l + r >> 1;
int x = dfs(l, mid), y = dfs(mid + 1, r);
return cmp(x, y);
}
void solve()
{
int n;
cin >> n;
int ans = dfs(1, n);
cout << "! " << ans << endl;
}
int main()
{
int T = 1;
scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
E1懒得写了...