E
考虑背包中一个物体进入dp过程即可 删去同理
#include <bits/stdc++.h>
using namespace std;
const int mod = 998244353;
#define int long long
signed main(){
ios::sync_with_stdio(false);cin.tie(nullptr);
int n,k;cin>>n>>k;
vector<int>dp(k+1);
dp[0]=1;
for(int i=1;i<=n;i++){
char c;cin>>c;
int x;cin>>x;
if(c=='-') for(int j=x;j<=k;j++)(dp[j]-=dp[j-x])%=mod;
else for(int j=k;j>=x;j--)(dp[j]+=dp[j-x])%=mod;
cout<<(dp[k]+mod)%mod<<'\n';
}
return 0;
}
F
二分答案 check x 轴枚举 y 轴直接维护出前缀 后缀 min max y坐标即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define all(x) (x).begin(),(x).end()
#define INF 0x3f3f3f3f3f3f3f3f
#define PII pair<int,int>
signed main(){
ios::sync_with_stdio(false);cin.tie(nullptr);
int n;cin>>n;
vector<PII>v;
vector<int>a,pre_mn(n,INF),pre_mx(n,-INF),suf_mn(n,INF),suf_mx(n,-INF);
for(int i=1;i<=n;i++){
int x,y;cin>>x>>y;
v.push_back({x,y});
a.push_back(x);
}
sort(all(v));
sort(all(a));
for(int i=0;i<n;i++){
if(i)pre_mn[i]=min(pre_mn[i],pre_mn[i-1]);
if(i)pre_mx[i]=max(pre_mx[i],pre_mx[i-1]);
pre_mn[i]=min(pre_mn[i],v[i].second);
pre_mx[i]=max(pre_mx[i],v[i].second);
}
for(int i=n-1;i>=0;i--){
if(i!=n-1)suf_mn[i]=min(suf_mn[i],suf_mn[i+1]);
if(i!=n-1)suf_mx[i]=max(suf_mx[i],suf_mx[i+1]);
suf_mn[i]=min(suf_mn[i],v[i].second);
suf_mx[i]=max(suf_mx[i],v[i].second);
}
int l=0,r=1e9;
while(l<r){
int mid=l+r+1>>1;
int x=mid,flag=0;
for(int i=0;i<n;i++){
int R=a[i]+x;
int it=lower_bound(all(a),R)-a.begin();
if(it==n)continue;
if(pre_mx[i]-suf_mn[it]>=x||suf_mx[it]-pre_mn[i]>=x){
flag=1;
break;
}
}
if(flag)l=mid;
else r=mid-1;
}
cout<<l<<endl;
return 0;
}
G
我们发现等差数列 公差恒为x
这样我们在输入的时候就可以-下标*x
就是来找一个数 让他们都相等 而不是等差数列就好求多了
然后发现具有单调性
二分是肯定的 check mid长度类是否有一个数让他们路径和<=k
这个数我们必然是选中位数的路径 肯定是最短的 然后就是权值线段树二分找中位数 以及 维护一些val cnt的计算路径和了
时间复杂度O(n2logn)足以通过本题
例外: 我们可以发现 他二分过程可以双指针来替代 时间复杂度可以降为O(nlogn) 如果不会写线段树二分 那我们可以用一些偷鸡小技巧求中位数比如pbds
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
#define int long long
#define PII pair<int,int>
struct node{
int l,r,v,cnt;
}tr[N<<2];
int n,m,a[N],mpp[N];
void pushup(int i) {
auto &u = tr[i], &l = tr[i << 1], &r = tr[i << 1 | 1];
u.v = l.v + r.v;
u.cnt = l.cnt + r.cnt;
}
void build(int i,int l,int r) {
tr[i].l = l, tr[i].r = r, tr[i].cnt = 0, tr[i].v = 0;
if (l == r) {
return;
}
int mid = l + r >> 1;
build(i << 1, l, mid);
build(i << 1 | 1, mid + 1, r);
}
void modify(int i,int x,int k,int k2) {
if (tr[i].l >= x && tr[i].r <= x) {
auto &u = tr[i];
u.v += k;
u.cnt += k2;
return;
}
if (tr[i].l > x || tr[i].r < x)return;
if (tr[i << 1].r >= x)modify(i << 1, x, k, k2);
if (tr[i << 1 | 1].l <= x)modify(i << 1 | 1, x, k, k2);
pushup(i);
}
int query(int i,int f) {
if (tr[i].l == tr[i].r) {
return tr[i].l;
}
if (tr[i << 1].cnt >= f)return query(i << 1, f);
else return query(i << 1 | 1, f - tr[i << 1].cnt);
}
PII query(int i,int l,int r) {
PII res = {0, 0};
if (tr[i].l >= l && tr[i].r <= r) {
auto &u = tr[i];
return {u.v, u.cnt};
}
if (tr[i].l > r || tr[i].r < l)return res;
if (tr[i << 1].r >= l) {
PII now = query(i << 1, l, r);
res.first += now.first;
res.second += now.second;
}
if (tr[i << 1 | 1].l <= r) {
PII now = query(i << 1 | 1, l, r);
res.first += now.first;
res.second += now.second;
}
return res;
}
void solve() {
cin >> n >> m;
map<int, int> mp;
for (int i = 1; i <= n; i++) {
cin >> a[i];
a[i] -= i;
mp[a[i]]++;
}
int idx = 0;
for (auto[pos, w]: mp) {
++idx;
mp[pos] = idx;
mpp[idx] = pos;
}
int ans = 1;
build(1, 1, n);
for (int i = 1, j = i; i <= n && j <= n; i++) {
while (j <= n) {
modify(1, mp[a[j]], a[j], 1);
int mid = j - i + 1;
int z = mpp[query(1, (mid + 1) / 2)];
auto[lv, lcnt]=query(1, 1, mp[z]);
auto[rv, rcnt]=query(1, mp[z] + 1, idx);
if (lcnt * z - lv + rv - rcnt * z <= m) {
ans = max(ans, mid);
j++;
} else {
modify(1, mp[a[i]], -a[i], -1);
modify(1, mp[a[j]], -a[j], -1);
break;
}
}
}
cout << ans << '\n';
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;cin >> t;
while (t--) {
solve();
}
}