挑战一天背完九上所有古诗文,咕咕咕
掉分场 计数dp 一句话题解:恰好 k k k个转换为钦定 k k k个,剩下随意,二项式反演然后 d p dp dp
计数dp/神必复杂度 几句话题解:首先枚举最小值,发现最小值最大只有 V k \frac{V}{k} kV,对每个最小值进行 d p dp dp,求出 d p [ i ] [ j ] dp[i][j] dp[i][j]表示前 i i i个,选了 j j j个,最小值大于等于枚举的值的方案数,发现可以双指针+前缀和做到 O ( n k ) O(nk) O(nk),最后差分统计答案,复杂度 O ( V k ) O(Vk) O(Vk)。 分数规划 一句话:套路题,二分比值然后树上背包。
决策单调性 比较有价值所以单独写了一篇博客。
星期五要上物理课 咕咕咕
BIT+扫描线 一眼题, 脑残边界写错好几次,调试三小时,我的做法貌似和网上大部分博客不太一样,一条竖线的贡献同样是经过横线的数量,如果有线坐标是 [ 0 , 1 e 6 ] [0,1e6] [0,1e6]则 a n s + + ans++ ans++,先是对竖线扫描线,对于靠左的横线,如果他的 r i ≥ x r_i \geq x ri≥x,会造成贡献,则对右端点排序,一个个加入树状数组,靠右的反之亦然。
#include<bits/stdc++.h> #define int long long #define N 1000015 #define rep(i,a,n) for (int i=a;i<=n;i++) #define per(i,a,n) for (int i=n;i>=a;i--) #define inf 0x3f3f3f3f #define pb push_back #define mp make_pair #define lowbit(i) ((i)&(-i)) #define VI vector<int> #define left fuck #define right ffuucckk #define All(x) x.begin(),x.end() #define debug(x) for(auto v:x) cout << v.l << ' ' << v.r << endl;cout <<"end" << endl; using namespace std; int n,m,t[N],ans; const int M = 1e6; struct hori{ int l,r,y; hori(){} hori(int a,int b,int c){l = a;r = b;y = c;} bool operator<(const hori&o) const{ if(l == 0) return o.r < r; if(r == M) return o.l > l; } }; struct ver{ int l,r,x; ver(){} ver(int a,int b,int c){l = a;r = b;x = c;} bool operator<(const ver&o) const{ return x < o.x; } }; struct BIT{ int a[N]; void add(int x,int d){ x++; for(;x<=M+1;x+=lowbit(x)) a[x]+=d; } int query(int x){ x++; int res = 0; for(;x;x-=lowbit(x)) {res+=a[x];} return res; } int query(int l,int r){ return query(r)-query(l-1); } }A,B; vector<ver> line; vector<hori> left,right; signed main(){ //freopen(".in","r",stdin); //freopen(".out","w",stdout); cin>>n>>m; rep(i,1,n){ int l,r,y; cin>>y>>l>>r; if(l == 0) left.pb(hori(l,r,y)); else if(r == M) right.pb(hori(l,r,y)); if(l==0&&r==M) ans++; } rep(i,1,m){ int l,r,y; cin>>y>>l>>r; if(l == 0&&r == M) ans++; line.pb(ver(l,r,y)); } sort(All(line));sort(All(left));sort(All(right)); int sz = line.size(),z = right.size(); int cur = 0; rep(i,0,sz-1){ while(cur < z&&right[cur].l <= line[i].x){ A.add(right[cur].y,1); cur++; } t[i] += A.query(line[i].l,line[i].r); } cur = 0,z = left.size(); per(i,0,sz-1){ while(cur < z&&left[cur].r >= line[i].x){ B.add(left[cur].y,1); cur++; } t[i] += B.query(line[i].l,line[i].r); } rep(i,0,sz-1) ans += max(t[i],0ll); printf("%lld\n",ans+1); return 0; }明天晚上打算掉场分。
线段树lazy 两个操作分别相当于 将深度 = k =k =k的节点左右儿子儿子互换 或者 将深度 > = k >=k >=k的节点左右儿子儿子互换。注意到一换就是一整层,用 l a z y [ x ] lazy[x] lazy[x]表示第 x x x层要不要换,在递归的时候传层数这个参数,如果当前层是 1 1 1,往下走时反着走。 分治 找到当前序列最小值,将所有值减去最小值,左右继续分治,或者直接取 r − l + 1 r-l+1 r−l+1做答案。
开学第一周效率有点低,争取一天三道题吧