A,B
签到题
C
题意:简单博弈
D
题意:有 1...n 的连续点,每个点你可以用固定数量的花费ci买固定数量的票ni,每向前走一个点需要花费一张票,初始在1点,没有票,问到达n点的最小花费。
思路:反向考虑,dp[i]表示从i点走到n点的最小花费,在i点时是没有票的。
dp转移:dp[i] = ci + min{dp[i+1],dp[i+2],...dp[i+ni]}
min 部分用线段树单点修改,区间查询最小值优化。
E
题意:求区间L到R中大于等于a,并且小于等于b的数的数量。
思路:简单主席树。
#include <bits/stdc++.h> using namespace std; #define N 100005 #define mid ((l+r)>>1) #define lc (tr[d].ch[0]) #define rc (tr[d].ch[1]) struct Tr{ int cnt,ch[2]; }tr[N<<2]; int cnt = 0,ro[N]; int newnode(){ ++cnt; tr[cnt].cnt = 0,tr[cnt].ch[0] = tr[cnt].ch[1] = 0; return cnt; } int build(int l,int r,int pre,int pos){ int d = newnode(); tr[d].cnt = tr[pre].cnt + 1; if(l == r) return d; lc = tr[pre].ch[0],rc = tr[pre].ch[1]; if(pos <= mid) lc = build(l,mid,tr[pre].ch[0],pos); else rc = build(mid+1,r,tr[pre].ch[1],pos); return d; } int query(int l,int r,int L,int R,int ro1,int ro2){ if(L == l && R == r){ return tr[ro2].cnt - tr[ro1].cnt; } if(R <= mid) return query(l,mid,L,R,tr[ro1].ch[0],tr[ro2].ch[0]); if(L > mid) return query(mid+1,r,L,R,tr[ro1].ch[1],tr[ro2].ch[1]); return query(l,mid,L,mid,tr[ro1].ch[0],tr[ro2].ch[0]) + query(mid+1,r,mid+1,R,tr[ro1].ch[1],tr[ro2].ch[1]); } int main() { int n,m; cin >> n >> m; int a,b; for(int i = 1;i <= n;++i) scanf("%d",&a),ro[i] = build(1,1000000,ro[i-1],a); int L,R; for(int i = 1;i <= m;++i){ scanf("%d%d%d%d",&a,&b,&L,&R); printf("%d ",query(1,1000000,a,b,ro[L-1],ro[R])); } return 0; }