26.10.6qbxt集训day6
T1

考虑固定全选三线射手,二分最小火力。
发现可以check。
点击查看代码
#include <iostream>
using std::cin;
using std::cout;
const int N = 1e6 + 10;
typedef long long ll;
int n;
ll a[N];
ll now[N];
ll b[N];
bool check(ll mid)
{
for (int i = 1; i <= n; ++i)
now[i] = b[i];
for (int i = 1; i <= n; ++i)
{
if (now[i] >= mid)
continue;
if (i == 1)
{
now[i + 1] -= std::min(mid - now[i], a[i]);
now[i] += std::min(mid - now[i], a[i]);
}
else
{
now[i + 1] -= std::min(std::min(now[i - 1] - mid, mid - now[i]), a[i]);
now[i] += std::min(std::min(now[i - 1] - mid, mid - now[i]), a[i]);
}
if (now[i] < mid)
return false;
}
return true;
}
template<typename T>
void rd(T &x)
{
x = 0;
int f = 1;
char c = getchar();
while (!isdigit(c))
{
if (c == '-')
f = -f;
c = getchar();
}
while (isdigit(c))
{
x = (x << 3) + (x << 1) - '0' + c;
c = getchar();
}
x *= f;
}
int main()
{
freopen("pea.in", "r", stdin);
freopen("pea.out", "w", stdout);
rd(n);
for (int i = 1; i <= n; ++i)
rd(a[i]);
for (int i = 1; i <= n; ++i)
b[i] = a[i - 1] + a[i] + a[i + 1];
ll l = 0, r = 1e14;
ll mid;
ll ans;
while (l <= r)
{
mid = (l + r) >> 1;
if (check(mid))
{
ans = mid;
l = mid + 1;
}
else
r = mid - 1;
}
cout << ans << '\n';
return 0;9
}
T2

考虑到如果没有 \(2\) 一定无解。
然后固定选一个 \(2\),枚举其它两个数 \(a_i, a_j\)。
要求出一组 \(x,y\) 使得 \(a_ix,a_jy\) 都是奇数,且 \(a_jy = a_ix + 2\)。
直接 exgcd。
点击查看代码
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
using std::cin;
using std::cout;
const int N = 1e3 + 10;
typedef long long ll;
struct Node
{
int p;
int a;
friend bool operator<(const Node &a, const Node &b)
{
return a.a < b.a;
}
} a[N];
int ans[4];
void exgcd(int a, int b, ll &x, ll &y)
{
if (b == 0)
return x = 1, y = 0, void();
exgcd(b, a % b, y, x);
y -= 1ll * a / b * x;
}
int gcd(int x, int y)
{
if (!x || !y)
return x | y;
int xx = __builtin_ctz(x);
int yy = __builtin_ctz(y);
int k = std::min(xx, yy);
int tmp;
y >>= yy;
while (x)
{
x >>= xx;
tmp = y - x;
xx = __builtin_ctz(tmp);
y = std::min(x, y), x = abs(tmp);
}
return y << k;
}
void rd(int &x)
{
x = 0;
int f = 1;
char c = getchar();
while (!isdigit(c))
{
if (c == '-')
f = -f;
c = getchar();
}
while (isdigit(c))
{
x = (x << 3) + (x << 1) - '0' + c;
c = getchar();
}
x *= f;
}
int main()
{
freopen("multiple.in", "r", stdin);
freopen("multiple.out", "w", stdout);
int n;
rd(n);
for (int i = 1; i <= n; ++i)
rd(a[i].a), a[i].p = i;
std::sort(a + 1, a + n + 1);
if (n < 3)
{
cout << "NO" << '\n';
return 0;
}
if (a[1].a == 1)
{
cout << "YES" << '\n';
ans[1] = a[1].p;
ans[2] = a[2].p;
ans[3] = a[3].p;
std::sort(ans + 1, ans + 3 + 1);
cout << ans[1] << ' ' << ans[2] << ' ' << ans[3] << '\n';
cout << 1 << '\n';
return 0;
}
if (a[1].a == 2)
{
for (int i = 2; i <= n; ++i)
{
for (int j = 2; j <= n; ++j)
{
if (i == j)
continue;
if ((!(a[i].a & 1)) || (!(a[j].a & 1)))
continue;
if (gcd(a[i].a, a[j].a) != 1)
continue;
ll x, y;
exgcd(a[i].a, a[j].a, x, y);
x = (x << 1);
y = (y << 1);
x = -x;
if (x <= 0)
{
ll t = (-x + a[j].a - 1) / a[j].a;
x += t * a[j].a, y += t * a[i].a;
if (x <= 0)
x += a[j].a, y += a[i].a;
}
if (y <= 0)
{
ll t = (-y + a[i].a - 1) / a[i].a;
x += t * a[j].a, y += t * a[i].a;
if (y <= 0)
x += a[j].a, y += a[i].a;
}
if (!(x & 1))
x += a[j].a, y += a[i].a;
if (x <= ((ll)1e18 + 1) / a[i].a)
{
cout << "YES" << '\n';
ans[1] = a[1].p;
ans[2] = a[i].p;
ans[3] = a[j].p;
std::sort(ans + 1, ans + 3 + 1);
cout << ans[1] << ' ' << ans[2] << ' ' << ans[3] << '\n';
cout << x * a[i].a - 1 << '\n';
return 0;
}
}
}
}
cout << "NO" << '\n';
return 0;
}
T3

似乎是懂了。
点击查看std
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
struct FastInput {
static constexpr int S = 1 << 16;
char buf[S]; int p = 0, len = 0;
inline char get() {
if (p == len) {
len = (int)fread(buf, 1, S, stdin); p = 0;
if (!len) return 0;
}
return buf[p++];
}
template<class T> inline void read(T &x) {
char c; do { c = get(); } while (c && c <= ' ');
x = 0; for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';
}
} input;
constexpr int MAXK = 3000000;
int n, q;
vector<i64> D, P, Q; // P_i = W_i-u_i, Q_i = W_i+v_i
// All products fit in signed 64 bits under the stated constraints.
inline i64 cross(int a, int b, int c, const vector<i64> &Y) {
return (D[b]-D[a])*(Y[c]-Y[a])-(Y[b]-Y[a])*(D[c]-D[a]);
}
inline bool slopeLess(int l1, int r1, int l2, int r2) {
return (Q[r1]-P[l1])*(D[r2]-D[l2])
< (Q[r2]-P[l2])*(D[r1]-D[l1]);
}
inline void pushUpper(vector<int> &h, int i) {
while (h.size() > 1 && cross(h[h.size()-2], h.back(), i, P) >= 0)
h.pop_back();
h.push_back(i);
}
inline void pushLowerReverse(vector<int> &h, int i) {
while (h.size() > 1 && cross(h[h.size()-2], h.back(), i, Q) >= 0)
h.pop_back();
h.push_back(i);
}
int tangentLeft(const vector<int> &h, int r) {
int lo = 0, hi = (int)h.size()-1;
while (lo < hi) {
int m = (lo+hi)/2;
if (slopeLess(h[m+1], r, h[m], r)) lo = m+1;
else hi = m;
}
int l = h[lo];
return (int)min<i64>(MAXK, (Q[r]-P[l])/(D[r]-D[l]));
}
int tangentRight(int l, const vector<int> &h) {
int lo = 0, hi = (int)h.size()-1;
while (lo < hi) {
int m = (lo+hi)/2;
if (slopeLess(l, h[m+1], l, h[m])) lo = m+1;
else hi = m;
}
int r = h[lo];
return (int)min<i64>(MAXK, (Q[r]-P[l])/(D[r]-D[l]));
}
struct Node {
int lo=0, hi=0, lc=-1, rc=-1, group=-1;
vector<int> prefix, suffix;
};
vector<Node> tree;
struct Group { int node; vector<int> byLeft, byRight; };
vector<Group> groups;
int build(int l, int r) {
int id = (int)tree.size(); tree.emplace_back();
tree[id].lo=l; tree[id].hi=r;
if (l==r) return id;
int mid=(l+r)/2;
int lc=build(l,mid), rc=build(mid+1,r);
Node &t=tree[id]; t.lc=lc; t.rc=rc;
int size=r-l+1;
t.prefix.resize(size); t.suffix.resize(size);
vector<int> h; h.reserve(min(size,64));
int best=MAXK;
for (int i=l; i<=r; ++i) {
if (i>l) best=min(best,tangentLeft(h,i));
t.prefix[i-l]=best;
pushUpper(h,i);
}
h.clear(); best=MAXK;
for (int i=r; i>=l; --i) {
if (i<r) best=min(best,tangentRight(i,h));
t.suffix[i-l]=best;
pushLowerReverse(h,i);
}
return id;
}
inline int prefixAnswer(int node, int r) {
const Node &t=tree[node];
return t.prefix.empty() ? MAXK : t.prefix[r-t.lo];
}
inline int suffixAnswer(int node, int l) {
const Node &t=tree[node];
return t.suffix.empty() ? MAXK : t.suffix[l-t.lo];
}
struct Query { int l, r, lo, hi, test; };
vector<Query> queries;
vector<i64> leftVal;
// The left points are inserted from mid down to l. This is an upper hull
// in decreasing X; the orientation sign is reversed from pushUpper().
inline void pushLeftReverse(vector<int> &h, int i) {
while (h.size()>1 && cross(h[h.size()-2],h.back(),i,P)<=0)
h.pop_back();
h.push_back(i);
}
inline void pushRight(vector<int> &h, int i) {
while (h.size()>1 && cross(h[h.size()-2],h.back(),i,Q)<=0)
h.pop_back();
h.push_back(i);
}
inline i64 lineP(int i, int k) { return P[i]-(i64)k*D[i]; }
inline i64 lineQ(int i, int k) { return Q[i]-(i64)k*D[i]; }
inline i64 maxLeft(const vector<int> &h, int k) {
int lo=0, hi=(int)h.size()-1;
while (lo<hi) {
int m=(lo+hi)/2;
if (lineP(h[m+1],k)>lineP(h[m],k)) lo=m+1;
else hi=m;
}
return lineP(h[lo],k);
}
inline i64 minRight(const vector<int> &h, int k) {
int lo=0, hi=(int)h.size()-1;
while (lo<hi) {
int m=(lo+hi)/2;
if (lineQ(h[m+1],k)<lineQ(h[m],k)) lo=m+1;
else hi=m;
}
return lineQ(h[lo],k);
}
// One parallel binary-search round. A query is assigned to exactly one node.
// Sweeps replace range-hull queries: O(size + active_queries * log size) per node.
void roundCheck(bool initial) {
vector<int> hull;
for (Group &g: groups) {
Node &t=tree[g.node];
int mid=tree[t.lc].hi;
bool active=false;
for (int id:g.byLeft) if (queries[id].lo<queries[id].hi) {active=true;break;}
if (!active) continue;
hull.clear();
int pos=mid;
for (int id:g.byLeft) {
Query &z=queries[id];
if (z.lo==z.hi) continue;
while (pos>=z.l) {pushLeftReverse(hull,pos);--pos;}
z.test=initial ? z.hi : z.lo+(z.hi-z.lo+1)/2;
leftVal[id]=maxLeft(hull,z.test);
}
hull.clear(); pos=mid+1;
for (int id:g.byRight) {
Query &z=queries[id];
if (z.lo==z.hi) continue;
while (pos<=z.r) {pushRight(hull,pos);++pos;}
bool ok=leftVal[id]<=minRight(hull,z.test);
if (initial) {
if (ok) z.lo=z.hi;
else --z.hi;
} else if (ok) z.lo=z.test;
else z.hi=z.test-1;
}
}
}
int main() {
input.read(n); input.read(q);
vector<int> U(n),V(n);
for (int &x:U) input.read(x);
for (int &x:V) input.read(x);
D.resize(n); vector<i64> W(n);
for (int i=1;i<n;++i) {int x;input.read(x);D[i]=D[i-1]+x;}
for (int i=1;i<n;++i) {int x;input.read(x);W[i]=W[i-1]+x;}
P.resize(n); Q.resize(n);
for (int i=0;i<n;++i) {P[i]=W[i]-U[i];Q[i]=W[i]+V[i];}
vector<int>().swap(U);vector<int>().swap(V);vector<i64>().swap(W);
tree.reserve(2*n);
int root=build(0,n-1);
queries.resize(q);leftVal.resize(q);
for (int id=0;id<q;++id) {
int l,r;input.read(l);input.read(r);--l;--r;
int p=root;
while (true) {
const Node &t=tree[p];
int mid=tree[t.lc].hi;
if (r<=mid) p=t.lc;
else if (l>mid) p=t.rc;
else break;
}
Node &t=tree[p];
int cap=min(suffixAnswer(t.lc,l),prefixAnswer(t.rc,r));
queries[id]={l,r,0,cap,0};
if (cap>0) {
if (t.group<0) {t.group=(int)groups.size(); groups.push_back({p,{},{}});}
groups[t.group].byLeft.push_back(id);
groups[t.group].byRight.push_back(id);
}
}
for (Group &g:groups) {
sort(g.byLeft.begin(),g.byLeft.end(),[](int a,int b){return queries[a].l>queries[b].l;});
sort(g.byRight.begin(),g.byRight.end(),[](int a,int b){return queries[a].r<queries[b].r;});
}
roundCheck(true); // First test the internal-interval upper bound.
for (int pass=0;pass<22;++pass) roundCheck(false);
string output;output.reserve(q*9);
for (const Query &z:queries) {output+=to_string(z.lo);output+='\n';}
fwrite(output.data(),1,output.size(),stdout);
}
T4

不懂
点击查看std
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
constexpr ll NEG=LLONG_MIN/4;
struct Edge{int v;ll w;};
struct Child{int v;ll w;};
int n,K;vector<vector<Edge>> adj;
mt19937 rng(20260927);
// f[j][0/1]: maximum weight, with j edges and structural sign +1/-1.
using DP=vector<array<ll,2>>;
inline void relax(ll &x,ll y){if(x<y)x=y;}
DP dfs(int u,int p){
vector<Child> ch;for(auto e:adj[u])if(e.v!=p)ch.push_back({e.v,e.w});
shuffle(ch.begin(),ch.end(),rng);
int d=(int)ch.size();
// A fixed optimal solution survives all these windows with probability >= 1-1e-10.
// Hoeffding for samples without replacement, union-bound over all prefixes/nodes.
int W=min(d+2,(int)ceil(sqrt(d*log(2.0*n*n*1e10)))+4);
int width=2*W+1;
vector<vector<ll>> cur(1,vector<ll>(width,NEG));cur[0][W]=0;
int total=0,processed=0;
for(auto e:ch){
DP f=dfs(e.v,u);
int lim=min(K,total+(int)f.size());
vector<vector<ll>> nxt(lim+1,vector<ll>(width,NEG));
for(int i=0;i<(int)cur.size();++i){
int r=min(processed,W);
for(int j=0;j<(int)f.size()&&i+j<=K;++j){
ll a=f[j][0],z=f[j][1],base=max(a,z);
int goal=i+j;
for(int b=-r;b<=r;++b){
ll old=cur[i][W+b];if(old==NEG)continue;
if(base!=NEG)relax(nxt[goal][W+b],old+base);
if(goal+1<=K){
if(a!=NEG&&b+1<=W)relax(nxt[goal+1][W+b+1],old+a+e.w);
if(z!=NEG&&b-1>=-W)relax(nxt[goal+1][W+b-1],old+z+e.w);
}
}
}
}
cur=move(nxt);total=min(K,total+(int)f.size());++processed;
}
DP result(cur.size(),{NEG,NEG});
for(int j=0;j<(int)cur.size();++j){result[j][0]=cur[j][W];if(W>=2)result[j][1]=cur[j][W+2];}
return result;
}
int main(){
#ifdef FILE_IO
freopen("matching.in","r",stdin);freopen("matching.out","w",stdout);
#endif
ios::sync_with_stdio(false);cin.tie(nullptr);
if(!(cin>>n>>K))return 0;adj.resize(n+1);
for(int i=1,u,v;i<n;++i){ll w;cin>>u>>v>>w;adj[u].push_back({v,w});adj[v].push_back({u,w});}
if(K&1){cout<<"Impossible\n";return 0;}
auto f=dfs(1,0);ll ans=NEG;if(K<(int)f.size())ans=max(f[K][0],f[K][1]);
if(ans==NEG)cout<<"Impossible\n";else cout<<ans<<'\n';
}
题解和今天讲的题:https://files.cnblogs.com/files/blogs/832279/2026_10_6_slide.zip?t=1791284375&download=true

从下往上读。

浙公网安备 33010602011771号