abc388
D
线段树板子改两行,支持单点查询,区间加就完了
没有思维难度,存板子没有码量
template <class Info>
struct SegmentTree {
struct Node {
int l, r;
Info info;
int tag;
};
std::vector<Node> tr;
SegmentTree() {};
SegmentTree(int n) {
init(n);
}
SegmentTree(std::vector<Info> & info) {
init(info);
}
void init(int n) {
tr.assign(n << 2, {});
build(0, n - 1);
}
void init(std::vector<Info> & info) {
int n = info.size();
tr.assign(n << 2, {});
std::function<void(int, int, int)> build = [&](int l, int r, int u) -> void {
tr[u] = {l, r, {},0};
if (l == r) {
tr[u].info = info[l];
return;
}
int mid = l + r >> 1;
build(l, mid, u << 1); build(mid + 1, r, u << 1 | 1);
pushup(u);
};
build(0, n - 1, 1);
}
void pushup(int u) {
tr[u].info = tr[u << 1].info + tr[u << 1 | 1].info;
}
void apply(int idx,int val){
tr[idx].info.sum += (tr[idx].r-tr[idx].l+1)*val;
tr[idx].tag += val;
}
void pushdown(int idx){
if(tr[idx].tag==0)return;
apply(idx*2,tr[idx].tag);
apply(idx*2+1,tr[idx].tag);
tr[idx].tag=0;
}
void build(int l, int r, int u = 1) {
tr[u] = {l, r, {}, -1};
if (l == r) {
return;
}
int mid = l + r >> 1;
build(l, mid, u << 1); build(mid + 1, r, u << 1 | 1);
pushup(u);
}
void modify(int p, const Info & info, bool set = false) {
int u = 1;
while (tr[u].l != tr[u].r) {
int mid = tr[u].l + tr[u].r >> 1;
if (p <= mid) {
u = u << 1;
} else {
u = u << 1 | 1;
}
}
if (set) {
tr[u].info = info;
} else {
tr[u].info = tr[u].info + info;
}
u >>= 1;
while (u) {
pushup(u);
u >>= 1;
}
}
//修改和查询要push_down
void change(int l,int r,int idx, int val){
if(l<=tr[idx].l && tr[idx].r <= r) {apply(idx,val);return;}
pushdown(idx);
int mid = (tr[idx].l + tr[idx].r) >> 1;
if(l<=mid) change(l,r,idx*2,val);
if(mid<r) change(l,r,idx*2+1,val);
pushup(idx);
}
Info query(int l, int r, int u = 1) {
if (l <= tr[u].l && tr[u].r <= r) {
return tr[u].info;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (r <= mid) {
return query(l, r, u << 1);
} else if (l > mid) {
return query(l, r, u << 1 | 1);
}
return query(l, r, u << 1) + query(l, r, u << 1 | 1);
}
};
struct Info{
ll sum;
Info():sum(0){}
Info(int x):sum(x){}
};
Info operator+(const Info l,const Info r){
Info res;
res.sum=l.sum+r.sum;
return res;
}
void solve(){
cin >> n;
vector<int> num(n+1), ans(n+1);
vector<Info> info(n+1);
For(i,1,n) cin >> num[i], info[i] = Info(0);
SegmentTree<Info> segs(info);
For(i,1,n){
x = num[i] + segs.query(i,i).sum;
int len = min(n-i,x);
segs.change(i+1,i+len,1,1);
ans[i] = x - len;
}
For(i,1,n) cout << ans[i] << " \n"[i == n];
}
E
题意:
一个非递减数组,一对数字定义为 $(a,b)$,$2a \le b$,问最多可以出多少对?
思路:
显然二分,对于每一个mid,显然让最小的 mid 个,和最大的 mid 个配对即可,如果无法配对成功就不行
void solve(){
cin >> n;
vector<int> num(n+1);
For(i,1,n) cin >> num[i];
// 能不能拿到 mid 对
auto check=[&](int mid) -> bool{
for(int i=1;i<=mid;++i){
int j = n - mid + i;
if(num[i]*2 > num[j]) return 0;
}
return 1;
};
int l = 0, r = n/2,mid,ans;
while(l<=r){
mid = (r+l)>>1;
if(check(mid)) l = mid + 1, ans = mid;
else r = mid-1;
}
cout << ans << '\n';
}
F
$dp_i$ 表示第 $i$ 个点能不能到,由于 $B \le 20$,所以可以直接考虑从前 $20$ 个位置的向量暴力转移,转移方程就是
$dp_i = \or_{j=a}^{b} dp_{i-j}$ ,使用矩阵快速幂优化即可,
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define all(v) v.begin(), v.end()
#define pb push_back
#define inf32 INT_MAX
#define inf64 LLONG_MAX
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int,int> pii;
mt19937_64 rng(time(0));
ll qmi(ll a, ll k, int m){ll res=1;while(k){if(k&1)res=res*a%m;a=a*a%m;k>>=1;}return res;}
const int Maxn = 20 + 5, Maxm = 2e4 + 5, N = 20, Mod = 998244353;
int n,m,k,x,y,z,q,A,B, m1, m2, l, r,u,v;
string s,Map[Maxn];
vector<int> G[Maxn];
struct Matrix{
bool a[Maxn][Maxn];
Matrix(){memset(a,0,sizeof a);}
Matrix operator*(const Matrix &t) const{
Matrix res;
For(k,1,N) For(i,1,N) For(j,1,N){
res.a[i][j] |= (a[i][k] & t.a[k][j]); // 矩阵乘法,i行j列 * i 行 j 列 的矩阵
}
return res;
}
}MG,MB, MG_pw[41], MB_pw[41];
bool f[Maxn], new_f[Maxn];
ll L[Maxm], R[Maxm];
void apply(int type, int n){
For(i,0,40){ // 矩阵快速幂,奇数次乘法得到向量优化乘 B^2
if((n>>i) &1){
memset(new_f, 0, sizeof new_f);
For(x,1,N) For(y,1,N){ // A[x][y] * f[y] = new_f[y]
new_f[x] |= (type ? MG_pw : MB_pw)[i].a[x][y] & f[y];
}
For(x,1,N) f[x] = new_f[x];
}
}
}
void solve(){
cin >> n >> m >> A >> B;
For(i,1,m) {cin >> L[i] >> R[i];}
For(i,A,B) MG.a[1][i] = 1;
For(i,2,N) MG.a[i][i-1] = 1;
For(i,2,N) MB.a[i][i-1] = 1;
MG_pw[0] = MG, MB_pw[0] = MB;
For(i,1,40){
MG_pw[i] = MG_pw[i-1] * MG_pw[i-1];
MB_pw[i] = MB_pw[i-1] * MB_pw[i-1];
}
f[1] = 1; int now = 1;
For(i,1,m){
// [now+1, l[i]-1] GOOD
// [l[i], r[i]] Bad
apply(1ll,L[i]-1-now); // 好矩阵
apply(0ll,R[i]-L[i]+1); // 坏矩阵
now = R[i];
}
apply(1ll,n - now);
puts(f[1]?"Yes":"No");
}
signed main() {
ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
// cin >> t;
while (t -- ) {
solve();
}
return 0;
}
/**
* 心中无女人
* 比赛自然神
* 模板第一页
* 忘掉心上人
**/

浙公网安备 33010602011771号