题目描述:有两个序列\(a, b\),两个序列都有\(n\)个数,而且这\(2n\)个数两两不一样,如今要将这两个序列里的数两两配对,组成\(n\)个数对,要求数对中\(a\)的数比\(b\)的数大的数对个数要比其它的多\(m\)个。问方案数。c++
solution
将这\(2n\)个数从小到大排,预处理出前\(i\)个数中\(a, b\)的个数\(suma, sumb\), \(f[i][j][k]\)表示前\(i\)个数,匹配了\(j\)对\(a>b\)的数对,还有\(k\)个\(a\)未匹配。
若是第\(i\)个数是\(a\)的数:数组
答案就是\(f[2*n+1][0][0]\),由于空间不够,全部要有滚动数组,并且卡常,因此要控制好枚举的范围。spa
时间复杂度:\(O(n^3)\)code
题目描述:有\(n\)个格子,每一个格子上有一条龙或一个公主,每条龙守着必定数量的金币,如今要从第一个格子出发,遇到龙时能够选择跳过,也能够选择杀死龙并拿走金币,若是遇到公主,假如杀龙的数量大于等于公主的要求,那么就要娶这个公主,已知最后一个格子是一个公主,而且娶且只娶最后一个公主,问最多能拿多少金币,输出方案。排序
solution
首先从后往前,算出到达每一个格子时最多能杀多少条龙,而后用一个堆维护最大的那几条龙便可。ip
时间复杂度:\(O(nlogn)\)字符串
题目描述:有\(n\)个球,每一个球的重量为\(w_i\),价值为\(c_i\),如今要取尽可能多的集合,每一个集合必需要有\(k\)个球,而且\(k\)个球的重量不一样,并且每一个集合的重量集合必须相同。问在最多能构成多少个集合,而且最大价值为多少。it
solution
统计每种重量的球有多少,从大到小排序,而后取前\(k\)种重量,对应的集合数为第\(k\)中重量的球的个数\(s\),而后算出球数大于等于\(s\)的重量中每种重量的最贵的\(s\)个球的总价值,而后取价值最大的\(k\)中重量。io
时间复杂度:\(O(nlogn)\)class
题目描述:有\(n\)个物品,每一个物品有不超过\(4\)种性质,有\(m\)个询问,每次询问拥有某些性质的物品有多少。
solution
性质的集合不超过\(n*2^4\)种,预处理出这些集合各有多少个物品拥有便可,用一个\(map\)就行了。
时间复杂度:\(O(2^4n+m)\)
题目描述:有一串珠子放在桌上,一共有\(n\)个珠子,其中有\(m\)个悬在桌边,每一个珠子有重量和价值,如今一次能够从两边取一个珠子(桌上或悬挂),若是取的是悬挂的珠子,则要从桌上移一个珠子使悬挂的珠子总数不变,当悬挂的珠子的总重量大于桌上的珠子的总重量乘\(k\)时,珠子会掉下来,问在保证珠子不掉下来的状况下,能拿走的最大总价值,输出方案。
solution
方案显然是先拿走悬挂的,而后再拿在桌上的。因此能够枚举最终悬挂的珠子的最下面一个是哪一个,而后二分出桌面上最多能拿走多少个珠子,而后贪心地拿就好。
时间复杂度:\(O(nlogn)\)
题目描述:有一个只有\(0, 1, 2\)的字符串,如今能够修改某些位置的字符,使得最终有\(a\)个\(0\),\(b\)个\(1\),问最少须要修改多少个字符,而且输出修改后的字符串。
solution
贪心。
时间复杂度:\(O(n)\)
题目描述:给定一棵树,树有边权,不断地删掉一条边,输出删掉的边的权值\(val\),取出分开的两棵树中点数较少的树(若是相同则取最小编号的点所在的树),这棵树的边权乘\(val\),另外一棵树的边权加\(val\)。强制在线。
solution
启发式拆树,拆的时候同时扩展两棵树,有一棵树搜完就停下,而后把这棵树的边权暴力更新,新建一个集合存这些点,旧的集合存另一棵树,在旧集合打上边权增量标记。
时间复杂度:\(O(nlogn)\)
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int mod=99990001; const int maxn=int(2e5)+100; struct LINK { int id, pre, next; }; int n, now; int h[maxn], nx[maxn]; LINK t[maxn*2]; int block[maxn]; int blockcnt; LL ans[maxn], mark[maxn]; queue<int> q[2]; int edge[2][maxn]; bool vis[maxn]; void join(int u, int v) { t[now].id=v; t[now].next=h[u]; t[now].pre=-1; if (h[u]!=-1) t[h[u]].pre=now; h[u]=now++; t[now].id=u; t[now].next=h[v]; t[now].pre=-1; if (h[v]!=-1) t[h[v]].pre=now; h[v]=now++; } void read() { scanf("%d", &n); for (int i=1; i<=n; ++i) h[i]=-1; for (int i=1; i<n; ++i) { int u, v, w; scanf("%d%d%d", &u, &v, &w); join(u, v); ans[i]=w; } } void bfs(int u, int v, int blockidx, LL w) { int minidx[2]={u, v}; edge[0][0]=edge[1][0]=0; nx[u]=h[u]; nx[v]=h[v]; while (!q[0].empty()) q[0].pop(); while (!q[1].empty()) q[1].pop(); q[0].push(u); q[1].push(v); while (!q[0].empty() && !q[1].empty()) { for (int j=0; j<2; ++j) { int cur=q[j].front(); bool flag=false; for (int i=nx[cur]; i>-1; i=nx[cur]=t[i].next) if (!vis[i/2+1]) { flag=true; minidx[j]=min(minidx[j], t[i].id); q[j].push(t[i].id); edge[j][++edge[j][0]]=i/2+1; nx[t[i].id]=h[t[i].id]; vis[i/2+1]=true; nx[cur]=t[i].next; break; } if (!flag) q[j].pop(); } } int idx=0; if ((!q[0].empty() && q[1].empty()) || (q[0].empty() && q[1].empty() && minidx[1]<minidx[0])) idx=1; ++blockcnt; for (int i=1; i<=edge[idx][0]; ++i) { ans[edge[idx][i]]=(ans[edge[idx][i]]+mark[blockidx])*w%mod; block[edge[idx][i]]=blockcnt; } mark[blockidx]=(mark[blockidx]+w)%mod; for (int j=0; j<2; ++j) for (int i=1; i<=edge[j][0]; ++i) vis[edge[j][i]]=false; } void edge_del(int idx) { for (int cur=idx*2-2; cur<idx*2; ++cur) { if (t[cur].pre!=-1) t[t[cur].pre].next=t[cur].next; else h[t[cur^1].id]=t[cur].next; if (t[cur].next!=-1) t[t[cur].next].pre=t[cur].pre; } } void solve() { blockcnt=1; for (int i=1; i<n; ++i) block[i]=1; for (int i=1; i<n; ++i) { int idx; scanf("%d", &idx); printf("%lld\n", (ans[idx]=(ans[idx]+mark[block[idx]])%mod)); fflush(stdout); edge_del(idx); bfs(t[(idx-1)*2].id, t[idx*2-1].id, block[idx], ans[idx]); } } int main() { read(); solve(); return 0; }
solution
仔细算一下就行了。
时间复杂度:\(O(1)\)