寒假做题记录
1/11:
树形DP+tarjan缩环:http://codeforces.com/contest/467/problem/D
题意是给n个字符串,再给m个转换,要求对n个字符串任意转换,使得最后n个串中r的数量最小,不区分大小写
输出r最小能有几个,满足条件的n个串的最小长度
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define ls i<<1 #define rs ls | 1 #define mid ((ll+rr)>>1) #define pii pair<int,int> #define MP make_pair typedef long long LL; const long long INF = 1e18+1LL; const double Pi = acos(-1.0); const int N = 1e6+10, M = 1e3+20, mod = 1e9+7, inf = 2e9+10; map<string , int> mp; int n,cnt,m,tt = 2,b[N]; char a[N],fi[N],se[N]; pair<int,int > p[N],F[N],P[N]; vector<int > G[N]; int head[N],low[N],dfn[N],tot,top,q[N],vis[N],inq[N],scc,belong[N]; struct ss{int to,next;}e[N * 2]; void add(int u,int v) { e[tt].next = head[u]; e[tt].to = v; head[u] = tt++; } void tarjan(int u) { dfn[u] = low[u] = ++tot; q[++top] = u; vis[u] = inq[u] = 1; for(int i = head[u]; i; i = e[i].next) { int to = e[i].to; if(!dfn[to]) { tarjan(to); low[u] = min(low[u],low[to]); } else if(inq[to]) low[u] = min(low[u],dfn[to]); } if(low[u] == dfn[u]) { scc++; do{ inq[q[top]] = 0; belong[q[top]] = scc; } while(u != q[top--]); } } void update(int u,pair<int ,int > now) { if(now.first < P[u].first) P[u] = now; else if(now.first == P[u].first && P[u].second > now.second) P[u] = now; } void dfs(int u) { vis[u] = 1; for(int i = 0; i < G[u].size(); ++i) { int to = G[u][i]; if(vis[to]) { update(u,P[to]);continue; } dfs(to); update(u,P[to]); } } int main() { scanf("%d",&n); for(int i = 1; i <= n; ++i) { scanf("%s",a); for(int j = strlen(a)-1; j >= 0; --j) a[j] = a[j] >= 'A' && a[j] <= 'Z' ? (a[j] - 'A' + 'a') : a[j]; int sum = 0; for(int j = strlen(a)-1; j >= 0; --j) if(a[j] == 'r') sum++; if(!mp[a]) mp[a] = ++cnt,p[cnt] = MP(sum,strlen(a)); b[i] = mp[a]; } scanf("%d",&m); for(int i = 1; i <= m; ++i) { scanf("%s%s",fi,se); for(int j = strlen(fi)-1; j >= 0; --j) fi[j] = fi[j] >= 'A' && fi[j] <= 'Z' ? (fi[j] - 'A' + 'a') : fi[j]; int sum = 0,sum2 = 0; for(int j = strlen(fi)-1; j >= 0; --j) if(fi[j] == 'r') sum++; for(int j = strlen(se)-1; j >= 0; --j) se[j] = se[j] >= 'A' && se[j] <= 'Z' ? (se[j] - 'A' + 'a') : se[j]; for(int j = strlen(se)-1; j >= 0; --j) if(se[j] == 'r') sum2++; if(!mp[fi]) mp[fi] = ++cnt, p[cnt] = MP(sum,strlen(fi)); if(!mp[se]) mp[se] = ++cnt, p[cnt] = MP(sum2,strlen(se)); add(mp[fi],mp[se]); } for(int i = 1; i <= cnt; ++i) if(!dfn[i]) tarjan(i); for(int i = 1; i <= scc; ++i) P[i] = MP(inf,inf); for(int i = 1; i <= cnt; ++i) update(belong[i],p[i]); for(int i = 1; i <= cnt; ++i) for(int j = head[i]; j; j = e[j].next) if(belong[i]!=belong[e[j].to]) { G[belong[i]].push_back(belong[e[j].to]); } memset(vis,0,sizeof(vis)); for(int i = 1; i <= scc; ++i) { if(!vis[i]) dfs(i); } LL l = 0, r = 0; for(int i = 1; i <= n; ++i) { l += P[belong[b[i]]].first; r += P[belong[b[i]]].second; } cout<<l<<" "<<r<<endl; return 0; }
1/12:
tyvj1982:http://www.tyvj.cn/p/1982 基础费用流
HDU5647:很好的一道树DP,分析可以看http://blog.csdn.net/snowy_smile/article/details/50935295
1/15:
网络流24题:餐巾计划问题 费用流
建模方法:
每天用完的餐巾纸和要用的餐巾纸是要分开来的
造一个源点S,Yi表示每天需要的用量,Xi表示每天用完的餐巾纸,那么S连向每一个Xi并用ri限制,每一个Yi连向T用ri限制
每天用完的餐巾可以选择留到下一天(Xi->Xi+1),不需要花费,
送到快洗部(Xi->Yi+m),费用为f,送到慢洗部(Xi->Yi+n),费用为s。
每天需要的餐巾除了刚刚洗好的餐巾,还可能是新购买的(S->Yi),费用为p。
网络流24题:负载平衡问题 费用流
【建模分析】
计算出每个仓库的盈余后,可以把问题转化为供求问题。
建立供求网络,把二分图X集合中所有节点看做供应节点,Y集合所有节点看做需求节点,在能一次搬运满足供需的Xi和Yj之间连接一条费用为1的有向边,表示搬运一个单位货物费用为1。
另外还要在Xi与相邻的Xj之间连接边,表示货物可以暂时搬运过去,不立即满足需求,费用也为1。最大流满足了所有的盈余和亏损供求平衡,最小费用就是最少搬运量。
网络流24题:分配问题
HDU5644:拆点的费用流
建模分析:先在将每个点拆成工作前(xi)工作后(yi)两点。
不考虑休假方式:s到y1连容量为k费用0的边,yi到t连容量为p[i]费用为0的边,yi到yi+1连容量为INF费用为0的边,第P个点以后连s到yi容量为INF费用为Q的边。
考虑休假方式:s到xi连容量为p[i]费用为0的边 表示每天能够过休假的人,xi到yi+tj连容量为INF费用为sj的边 表示休假后继续工作。
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define ls i<<1 #define rs ls | 1 #define mid ((ll+rr)>>1) #define pii pair<int,int> #define MP make_pair typedef long long LL; const long long INF = 1e18+1LL; const double Pi = acos(-1.0); const int N = 1e6+10, M = 1e3+20, mod = 1e9+7, inf = 2e9+10; int S,T,ans1; int P[N],m,p,Q,s,t; int n,k,head[40005],q[40005],dis[40005],from[40005],a[40005],cnt=1,sum,ans; bool inq[40005]; struct data{int from,to,next,v,c;}e[100001]; void ins(int u,int v,int w,int c) { cnt++; e[cnt].from=u;e[cnt].to=v; e[cnt].v=w;e[cnt].c=c; e[cnt].next=head[u];head[u]=cnt; } void insert(int u,int v,int w,int c) {ins(u,v,w,c);ins(v,u,0,-c);} bool spfa() { for(int i=0;i<=T;i++)dis[i]=inf; int t=0,w=1,i,now; dis[0]=q[0]=0;inq[0]=1; while(t!=w) { now=q[t];t++;if(t==20001)t=0; for(int i=head[now];i;i=e[i].next) { if(e[i].v&&dis[e[i].to]>dis[now]+e[i].c) { from[e[i].to]=i; dis[e[i].to]=dis[now]+e[i].c; if(!inq[e[i].to]) { inq[e[i].to]=1; q[w++]=e[i].to; if(w==20001)w=0; } } } inq[now]=0; } if(dis[T]==inf)return 0;return 1; } void mcf() { int i,x=inf; i=from[T]; while(i) { x=min(e[i].v,x); i=from[e[i].from]; } i=from[T]; ans1+=x; while(i) { e[i].v-=x; e[i^1].v+=x; ans+=x*e[i].c; i=from[e[i].from]; } } int main() { int cas = 1; scanf("%d",&cas); while(cas--) { scanf("%d%d",&n,&k); S = 0 , T = 2*n+1;sum=0; cnt = 1;memset(head,0,sizeof(head)); for(int i = 1; i <= n; ++i)scanf("%d",&P[i]),sum+=P[i],insert(i+n,T,P[i],0); insert(S,1+n,k,0); scanf("%d%d%d",&m,&p,&Q); for(int i = p; i <= n; ++i) insert(S,i+n,inf,Q); for(int i = 1; i <= m; ++i){ scanf("%d%d",&s,&t); for(int j = 1; j <= n; ++j) { if(j+t+n<=n*2) insert(j,j+n+t,inf,s); } } for(int i = 1; i <= n; ++i) insert(S,i,P[i],0); for(int i = 1; i < n; ++i) insert(i+n,i+n+1,inf,0); ans = 0;ans1 = 0; while(spfa()) mcf(); if(ans1 == sum) cout<<ans<<endl; else puts("No solution"); } return 0; }
1/21:
HDU5593 树形DP
这是一颗固定根节点的树,要算每个点与其距离不超过k的点个数,数的办法无非向下向上数,向下数的就是基础DP,
设定dp[i][k]表示以i为根节点向下走k步能够到达的点的个数,向上的话,由于k这么小直接暴力向上走就可以了
这题可以分治写,待补
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define ls i<<1 #define rs ls | 1 #define mid ((ll+rr)>>1) #define pii pair<int,int> #define MP make_pair typedef long long LL; const long long INF = 1e18+1LL; const double Pi = acos(-1.0); const int N = 1e6+10, M = 1e3+20, mod = 1e9+7, inf = 2e9+10; int n,k,A,B; int dp[N][12]; vector<int > G[N]; void dfs(int u,int fa) { dp[u][0] = 1; for(int i = 0; i < G[u].size(); ++i) { int to = G[u][i]; if(to == fa) continue; dfs(to,u); dp[u][1]+=1; for(int j = 2; j <= k; ++j) dp[u][j] += dp[to][j-1]; } } int f[N]; int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d%d%d",&n,&k,&A,&B); for(int i = 1; i <= n; ++i) G[i].clear(); memset(f,0,sizeof(f)); f[1] = 0; for(int i = 2; i <= n; ++i) { f[i] = (1ll*A*i%(i-1)+B)%(i-1)+1; G[(1ll*A*i%(i-1)+B)%(i-1)+1].push_back(i); } memset(dp,0,sizeof(dp)); dfs(1,0); for(int i = 1; i <= n; ++i) for(int j = 1; j <= k; ++j) dp[i][j] += dp[i][j-1]; for(int i = 1; i <= n; ++i) { int cnt = 1,tmp = i; while(f[tmp]&&cnt<=k) { dp[i][k] += (dp[f[tmp]][k-cnt]); if(k-cnt-1>=0) dp[i][k] -= dp[tmp][k-cnt-1]; tmp = f[tmp]; cnt++; } } int ans = 0; for(int i = 1; i <= n; ++i) { ans ^= dp[i][k]; } printf("%d\n",ans); } return 0; }
1/25:
Codeforces Round #392 (Div. 2) D、E
2/1:
整理树链剖分
2/6:
CDOJ卿学姐种美丽的花:两个树状数组维护
2/8:
codeforces #307div.2 E.GukiZ and GukiZiana 分块+二分
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define ls i<<1 #define rs ls | 1 #define mid ((ll+rr)>>1) #define pii pair<int,int> #define MP make_pair typedef long long LL; const long long INF = 1e18+1LL; const double Pi = acos(-1.0); const int N = 5e6+10, M = 1e3+20, mod = 1e9+7, inf = 2e9+10; int n,q,m,block,pos[N]; LL add[N],a[N]; pair<LL ,int > b[N]; void init() { for(int i = 1; i <= m; ++i) { for(int j = (i-1)*block+1; j <= min(n,i*block); ++j) b[j] = MP(a[j],j); sort(b+(i-1)*block+1, b + min(n,i*block) + 1); } } void update(int l,int r,int c) { if(pos[l] == pos[r]) { for(int i = l; i <= r; ++i) a[i] += c; for(int i = block*(pos[l]-1)+1; i <= min(pos[l]*block,n); ++i) b[i] = MP(a[i],i); sort(b+block*(pos[l]-1)+1,b+min(pos[l]*block,n)+1); } else { for(int i = pos[l]+1; i <= (pos[r]-1); ++i) add[i]+=c; for(int i = l; i <= pos[l]*block; ++i) a[i] += c; for(int i = block*(pos[l]-1)+1; i <= pos[l]*block; ++i) b[i] = MP(a[i],i); sort(b+block*(pos[l]-1)+1,b+pos[l]*block+1); for(int i = (pos[r]-1)*block+1; i <= r; ++i) a[i] += c; for(int i = block*(pos[r]-1)+1; i <= min(pos[r]*block,n); ++i) b[i] = MP(a[i],i); sort(b+block*(pos[r]-1)+1,b+min(pos[r]*block,n)+1); } } int query(LL x) { int mi = inf, mx = -1; for(int i = 1; i <= m; ++i) { int pos1 = lower_bound(b+(i-1)*block+1,b+min(n,i*block)+1,make_pair(x-add[i],-1)) - b; int pos2 = lower_bound(b+(i-1)*block+1,b+min(n,i*block)+1,MP(x-add[i]+1,-1)) - b; if(b[pos1].first == x-add[i] && pos1 != min(n,i*block)+1) { mi = min(b[pos1].second,mi); mx = max(b[pos1].second,mx); } if(b[pos2-1].first == x-add[i]&& pos2 != (i-1)*block+1) { mi = min(b[pos2-1].second,mi); mx = max(b[pos2-1].second,mx); } } if(mx == -1 || mi == inf) return -1; else return mx - mi; } int main() { scanf("%d%d",&n,&q); block = (int) sqrt(n); if(n%block) m = n/block+1;else m = n/block; for(int i = 1; i <= n; ++i) scanf("%I64d",&a[i]),pos[i] = (i-1)/block+1; init(); while(q--) { int op,l,r; LL c; scanf("%d",&op); if(op == 1) { scanf("%d%d%I64d",&l,&r,&c); update(l,r,c); } else { LL x; scanf("%I64d",&x); cout<<query(x)<<endl; } } // for(int i = 1; i <= n; ++i) cout<<b[i].first<<" ";cout<<endl; return 0; } /* 8 5 1 1 1 2 1 3 1 1 2 1 1 1 8 1 2 2 1 2 5 2 2 4 */