首页 > 代码库 > 2014 8.7 第8场个人 排位
2014 8.7 第8场个人 排位
2024-07-16 09:30:55 222人阅读
FZU 2079 最大获利(dp)
自己很难想到,囧
dp[i]表示处理完前i 个点的最大收益。
有两种情况:
(1)第i 个点不投资,那么dp[i] = dp[i - 1]
(2)第i 个点投资,那么dp[i] = max(dp[k] + get(k + 1,i) - sigma(c[j]) (k + 1 <= j <= i))(0 < k <
i)
这个的意思是,[k + 1,i]点选择全部投资,所以sigma(c[j])表示每个点都投资了,get(k +
1,i)的意思是,[k + 1,i]完全包含了的给出区间的总价值
第二步需要优化,我们发现,任意一个dp[i]的转移dp[k],sigma(c[j]),即dp[k] 减去了从k
+ 1,i 的每个数c[i],所以每做到一个数i,给1..i - 1 中的每个dp 值减去c[i](因为以后要用
某个dp 转移的话,后面的每个数都被减了一次)。第二个是收益[Li,Ri,Pi],同样的方法,
选择了dp[k],k < Li 的话,意味着get(k + 1,i)增加了Pi,所以给1...Li - 1 的每个dp 值加上Pi
赛后代码:
view code#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <algorithm>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1const int N = 22222;int n, m, a[N], dp[N], col[N<<2], Max[N<<2];struct seg{ int l, r, w; seg() {} seg(int l, int r, int w):l(l),r(r),w(w) {} bool operator < (const seg &o) const { return r<o.r||(o.r==r&&l>o.l); }}e[N];void Down(int rt){ if(col[rt]) { Max[rt<<1] += col[rt]; Max[rt<<1|1] += col[rt]; col[rt<<1] += col[rt]; col[rt<<1|1] += col[rt]; col[rt] = 0; }}void update(int L, int R, int c, int l, int r, int rt){ if(L<=l && R>=r) { Max[rt] += c; col[rt] += c; return ; } Down(rt); int m=(l+r)>>1; if(L<=m) update(L, R, c, lson); if(R>m) update(L, R, c, rson); Max[rt] = max(Max[rt<<1], Max[rt<<1|1]);}int query(int L, int R, int l, int r, int rt){ if(L<=l && R>=r) return Max[rt]; int m = (l+r)>>1, ans = 0; if(L<=m) ans = max(query(L,R,lson), ans); if(R>m) ans = max(query(L,R,rson), ans); return ans;}void solve(){ memset(col, 0, sizeof(col)); memset(Max, 0, sizeof(Max)); for(int i=1; i<=n; i++) scanf("%d", a+i); for(int i=0; i<m; i++) scanf("%d%d%d", &e[i].l, &e[i].r, &e[i].w); sort(e, e+m); int i=1, j=0; for(; i<=n; i++) { update(0, i-1, -a[i], 0, n, 1); while(j<m && e[j].r<=i) { update(0, e[j].l-1, e[j].w, 0, n, 1); j++; } dp[i] = max(dp[i-1], query(0, i-1, 0, n, 1)); update(i, i, dp[i], 0, n, 1); } printf("%d\n", dp[n]);}int main(){// freopen("in.txt", "r", stdin); while(scanf("%d%d", &n, &m)>0 ) solve(); return 0;}
FZU 2056 最大正方形(二分,水题)
刚开始看题目还以为是长方形,最近老是看错题目
view code#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <cmath>#include <algorithm>#include <map>#include <vector>#include <string>using namespace std;typedef long long ll;const int INF = 0x3f3f3f3f;const int N = 1010;int mat[N][N], sum[N][N];int _, n, m, lim, ansn, ansm;bool is_ok(int len){ for(int i=len; i<=n; i++) { for(int j=len; j<=m; j++) { if(sum[i][j]+sum[i-len][j-len]-sum[i-len][j]-sum[i][j-len]<=lim) return 1; } } return 0;}void solve(){ scanf("%d%d%d", &n, &m, &lim); for(int i=1 ;i<=n ;i++) { for(int j=1; j<=m; j++) { scanf("%d", &mat[i][j]); sum[i][j] = sum[i-1][j]+sum[i][j-1] - sum[i-1][j-1] +mat[i][j]; } } int l=1, r=min(n, m), ans=0; while(l<=r) { int mid = (l+r)>>1; if(is_ok(mid)) ans = mid, l = mid+1; else r = mid-1; } printf("%d\n", ans*ans);}int main(){// freopen("in", "r", stdin); cin>>_; while(_--) solve(); return 0;}
FZU 2082
方法一:树链剖分最入门的题目,复杂度nlognlogn(第一次听说树链剖分)
方法二:随便选一个点作为root,dfs 一次求出root 到某个点的距离,并且得到dfs 序。
一个显然的事实:dis(u,v) = dis(root,u) + dis(root,v) - 2 * dis(root,lca(u,v)),因此任意两个点的
距离可以直接用到root 的距离算出来。dis(root,i)表示从根到i 的距离,dis(u,v)是u 到v 的距
离
修改操作是,如果给(fa(u),u)这条边增加了一个值x,那么dis(root,u)增加x,且其后代每个
点的dis(root,i)都增加了x,这个操作,直接用得到的dfs 序维护即可
(把dfs序列得到的dis弄到线段树上,对于root所有子节点增加x,相当于成段更新,因为root的所有子节点是连续的线段)!!
view code#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1typedef long long ll;const int N = 50010;int n, m, c, pre[N], id[N], now;int E[N<<1], pos, R[N], d[N<<1][21];//E得到的dfs序列用来求Lcaint LL[N], RR[N], EE[N], ppos;//EE得到的序列是用于线段树,EE[i]的字结点位于区间LL[i]+1,RR[i]-1.bool vis[N];ll dp[N], sum[N<<2];struct edge{ int u, v;ll w; int p; edge() {} edge(int u, int v,ll w, int p):u(u), v(v), w(w), p(p) {}}e[N<<1];int ecnt, tot;void init_RMQ(){ for(int i=0; i<pos; i++) d[i][0] = E[i]; for(int j=1; (1<<j)<pos; j++) for(int i=0; i+(1<<j)-1<pos; i++) d[i][j] = min(d[i][j-1], d[i+(1<<(j-1))][j-1]);}ll RMQ(int L, int R){ int k=0; while((1<<(k+1)) <= R-L+1) k++; return min(d[L][k], d[R-(1<<k)+1][k]);}void dfs(int u, int h){ vis[u] = 1; id[u] = now++; R[id[u]] = pos; E[pos++] = id[u]; LL[id[u]] = tot; EE[tot++] = id[u]; dp[id[u]] = h; for(int i=pre[u]; ~i; i=e[i].p) { int v = e[i].v; if(vis[v]) continue; dfs(v, h+e[i].w); E[pos++] = id[u]; } RR[id[u]]=tot;}void build(int l, int r, int rt){ if(l==r) { sum[rt] = dp[EE[pos++]]; return ; } int m = (l+r)>>1; build(lson); build(rson); sum[rt] = 0;}void Down(int rt){ if(sum[rt]) { sum[rt<<1|1]+=sum[rt]; sum[rt<<1] += sum[rt]; sum[rt] = 0; }}ll query(int p, int l, int r, int rt){ if(l==r) return sum[rt]; Down(rt); int m = (l+r)>>1; ll ans = 0; if(p<=m) ans = query(p, lson); else ans = query(p, rson); return ans;}void update(int L, int R, int c,int l, int r, int rt){ if(L<=l && R>=r) { sum[rt] += c; return ; } Down(rt); int m = (l+r)>>1; if(L<=m) update(L, R, c, lson); if(R>m) update(L, R, c, rson);}void addedge(int u, int v, int w){ e[ecnt] = edge(u, v, w, pre[u]); pre[u] = ecnt++; e[ecnt] = edge(v, u, w, pre[v]); pre[v] = ecnt++;}void solve(){ memset(pre, -1, sizeof(pre)); ecnt = 0, tot=1; int u, v, w, flag; for(int i=1; i<n; i++) { scanf("%d%d%d", &u, &v, &w); addedge(u,v,w); } now = 1; pos = 0, ppos = 1; memset(vis, 0, sizeof(vis)); dfs(1, 0); init_RMQ(); pos = 1; build(1, n, 1); while(m--) { scanf("%d%d%d", &flag, &u, &v); if(flag) { u = id[u], v = id[v]; int lca = RMQ(min(R[u], R[v]), max(R[u],R[v])); ll ans = query(LL[u], 1, n, 1) + query(LL[v], 1, n, 1) - 2*query(LL[lca], 1, n, 1); printf("%I64d\n", ans); } else { int ndis = v, c = 2*u-1; u = id[e[c].u], v = id[e[c].v]; if(query(LL[u], 1, n, 1)>query(LL[v], 1, n, 1)) update(LL[u], RR[u]-1, ndis-e[c].w, 1, n, 1); else update(LL[v], RR[v]-1, ndis-e[c].w, 1, n, 1); e[c].w = e[c-1].w = ndis; } }}int main(){// freopen("in.txt","r",stdin); while(scanf("%d%d", &n, &m)>0) solve(); return 0;}
FZU 2057 家谱(简单的遍历)
view code#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <cmath>#include <algorithm>#include <map>#include <vector>#include <string>using namespace std;typedef long long ll;const int INF = 0x3f3f3f3f;const int N = 10010;int _, n, m, p[N];struct edge{ int fa, ma, flag; edge() {} edge(int fa, int ma, int flag):fa(fa),ma(ma),flag(flag) {}}e[N];bool dfs(int u, int t){ if(u==0) return 0; if(u==t) return 1; if(dfs(e[u].fa, t)) { p[u] = e[u].fa; return 1;// printf("") } else if(dfs(e[u].ma, t)) { p[u] = e[u].ma; return 1; } return 0;}void visit(int u, int t){ if(u==t) { printf(e[u].flag?"F":"M"); return; } printf(e[u].flag?"F":"M"); visit(p[u], t);}void solve(){ scanf("%d", &n); int k = n/2, t, u, v; for(int i=0; i<=n; i++) e[i] = edge(0, 0, 0); for(int i=0; i<k; i++) { scanf("%d%d%d", &t, &u, &v); e[t].fa = u; e[t].ma = v; e[u].flag = 1; } scanf("%d", &m); for(int i=0; i<m; i++) { scanf("%d%d", &u, &v); if(dfs(u,v)) { printf("1 "); visit(p[u],v); puts(""); } else if(dfs(v, u)) { printf("0 "); visit(p[v],u); puts(""); } else puts("Relative"); }}int main(){// freopen("in", "r", stdin); cin>>_; while(_--) solve(); return 0;}
FZU 2059 MM(暴力)
因为最多只有10次修改,就把当作最多有10个子case就好了
view code#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <algorithm>using namespace std;const int INF = 0x3f3f3f3f;const int N = 100010;int _, n, m;int a[N], L[N], R[N], ma[N], mcnt, Max[N];int find(int ser){ int l = 0, r = mcnt-1, ans = -1; while(l<=r) { int m = (l+r)>>1; if(ma[m]==ser) return m; if(ser<ma[m]) ans = m, r = m-1; else l = m+1; } return ans;}void init(){ a[0] = a[n+1] = -INF; mcnt = 1; for(int i=1; i<=n; i++) ma[i-1] = a[i]; sort(ma, ma+n); for(int i=1; i<n; i++) if(ma[i]!=ma[i-1]) ma[mcnt++] = ma[i]; int pos, id; for(int i=1; i<=n; i++) { L[i] = i; pos = i-1; while(a[i]<=a[pos]) L[i]=L[pos], pos=L[pos]-1; } memset(Max, 0, sizeof(Max)); for(int i=n; i>0; i--) { R[i] = i; pos = i+1; while(a[i]<=a[pos]) R[i]=R[pos], pos=R[pos]+1; id = find(a[i]); Max[id] = max(Max[id], R[i]-L[i]+1); } for(int i=mcnt-1; i>0; i--) { Max[i-1] = max(Max[i], Max[i-1]); }// for(int i=1; i<=n; i++) printf("%d , %d\n", L[i], R[i]);}int main(){// freopen("in.txt", "r", stdin); while(scanf("%d%d", &n, &m)>0) { for(int i=1; i<=n; i++) scanf("%d", a+i); int f, x, y; init(); for(int i=0; i<m; i++) { scanf("%d%d", &f, &x); if(f==1) { int id = find(x); if(id>=0) printf("%d\n", Max[id]); else printf("0\n"); } else { scanf("%d", &y); a[x] = y; init(); } } } return 0;}
FZU 2060 The Sum of Sub-matrices(状态压缩dp,不会)
FZU 2030 括号问题(dfs/dp)
view code#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <cmath>#include <algorithm>#include <map>#include <vector>#include <string>using namespace std;typedef long long ll;const int INF = 0x3f3f3f3f;int n, m, sum[50], a[50];char s[50];int dfs(int now, int num){ if(num<0) return 0; if(now>=n) { if(num==0) return 1; else return 0; } int ans = 0; if(s[now]==‘(‘) ans= dfs(now+1, num+1); else if(s[now]==‘)‘ ) { ans = dfs(now+1, num-1); } else { ans += dfs(now+1, num+1); ans += dfs(now+1, num-1); }// printf("%d , %d\n", now, ans); return ans;}void solve(){ n = strlen(s); printf("%d\n", dfs(0, 0));}int main(){// freopen("in", "r", stdin); while(scanf("%s", s)>0) solve(); return 0;}