集训Day2
雅礼集训2017Day2
T1
给你一个水箱,水箱里有n-1个挡板,水遵循物理定律
给你m个条件,表示第i个格子上面y+1高度的地方有或没有水
现在给你无限的水从任意地方往下倒,问最多满足多少条件
n,m 1e5
SOL:
考虑答案的表示方法,肯定是类似于dp["区间1到n"]这种的
“区间1到n”这个东西我们可以状压,就过了20%
另外10%的数据只有“有水”的条件 我们cout<<m
另外30%的n平方做法肯定是要用到dp(我没有想出来这个东西怎么搞到n平方)
。。。
这里是全知全能的XiongGod提供的一种n平方做法
对于每一个条件,可以将其视为l到r区间的最高/最低高度为x;
把所有条件记录下来后就成了区间选择问题的版题,分成上下界两种讨论dp就好了
考虑暴力碾标算
一个区间能能不能“有水”取决于中间最长的那个木板
于是可以考虑递归建一棵“线段树”
这样一个区间的问题就可以递归到左右儿子解决
且因为这是棵线段树,最多nlogn个点
然后树形DP
$d[i]$表示i节点水没有漫出去的情况
$f[i]$表示i节点水漫出去的情况
式子由于...这是要给学妹(实际只有学弟吧?)看的
所以你们自己推吧
T2
一个100*100的棋盘,有地方有障碍
Alice和Bob两个人玩游戏,Alice放一个棋子,Bob先手二人轮流移动棋子
要求:不能移到障碍上且走过的地方不能走
不能动就输了
求Alice的必胜点
SOL:
原题啊...
将棋盘黑白染色建出二分图 有障碍直接跳过就行了
考虑对于一个完美匹配,Bob(先手)按匹配边走就可以了
对于不完美的最大匹配,Alice可以把棋放在“不一定是最大匹配”的地方,让Bob走非匹配边,自己走匹配边
现在就是要考虑如何求这个“不一定是最大匹配”的点
跑完dinic,从S开始跑未满流的边,跑到左边的且非S的点就是“不一定是最大匹配”的
T开始跑未满流的边,跑到右边且非T的点就是“不一定是最大匹配的”
为什么正确可以通过交错路定理来证明一下
时间复杂度是O(您用的二分图匹配算法 + 棋盘大小)
100 + 100 + 0 = 200?
T3前30随便写可是没时间写了...
话说是不是上午时间不够啊
如果再给我半个小时就是100 + 100 + 30 = 230了(再次大众分
#include<bits/stdc++.h> #define LL long long inline int read() { int x = 0,f = 1; char ch = getchar(); for(; !isdigit(ch); ch = getchar())if(ch == '-')f = -f; for(; isdigit(ch); x = 10 * x + ch - '0',ch = getchar()); return x * f; } const int maxn = 2e5 + 10,inf = 2147483233; int n,m,N; int fa[maxn],bot[maxn],top[maxn],dx[maxn]; int ST[20][maxn]; int son[maxn][2]; int f[maxn],d[maxn]; struct block { int h,pos; } hs[maxn]; bool cmp(const block &a,const block &b) { if(a.h == b.h)return a.pos < b.pos; return a.h < b.h; } struct info { int h,type; bool operator < (const info &a)const { if(h == a.h)return type < a.type; return h < a.h; } }; std::vector<info> vec[maxn]; inline int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } int main() { int T = read(); while(T--) { n = read(),m = read(); N = n; memset(dx,0,sizeof(dx)); memset(fa,0,sizeof(fa)); memset(f,0,sizeof(f)); memset(d,0,sizeof(d)); int S,T,sum,sz,tmp; for(int i=1; i<n; i++) { hs[i].h = read(); hs[i].pos = i; } std::sort(hs + 1,hs + n,cmp); bot[0] = inf; for(int i=1; i<=n; i++)top[i] = i,fa[i] = i; for(int i=1; i<n; i++) { int fx = find(hs[i].pos),fy = find(hs[i].pos + 1); bot[++N] = hs[i].h; ST[0][N] = 0; ST[0][top[fx]] = N; ST[0][top[fy]] = N; son[N][0] = top[fx],son[N][1] = top[fy]; fa[fy] = fx; top[fx] = N; } for(int i=1; i<=N; i++)vec[i].clear(); for(int i=1; i<=18; i++) for(int j=1; j<=N; j++) ST[i][j]=ST[i-1][ST[i-1][j]]; int x,y,k; for(int i=1; i<=m; i++) { x = read(),y = read(),k = read(); for(int j=18; j>=0; j--) if(bot[ST[j][x]] <= y)x = ST[j][x]; vec[x].push_back((info) {y,k}); dx[x] += !k; } for(int i=1; i<=N; i++)std::sort(vec[i].begin(),vec[i].end()); for(int i=1; i<=N; i++) { if(!vec[i].empty()) { sz = vec[i].size(); S = 0; d[i] = sum = dx[i] + ( i > n ? f[son[i][0]] + f[son[i][1]] : 0); while(S < sz) { T = S; tmp = (vec[i][T].type ? 1 : -1); while(T + 1 < sz && vec[i][T+1].h == vec[i][T].h) ++T,tmp += (vec[i][T].type ? 1 : -1); sum += tmp; d[i] = std::max(d[i],sum); S = T + 1; } f[i] = sum; } if(i > n) { d[i] = std::max(d[i],dx[i] + d[son[i][0]] + d[son[i][1]]); f[i] = std::max(f[i],f[son[i][0]] + f[son[i][1]]); } } printf("%d\n",d[N]); } }
#include<bits/stdc++.h> using namespace std; const int _MAX = 110,MAX_POINT = 21010,MAXE = 1000010,inf = 2147483233; const int dx[] = {0,1,-1,0,0}; const int dy[] = {0,0,0,1,-1}; int ans[MAX_POINT]; int m,n; int S = 0,T = MAX_POINT - 1; char s[_MAX][_MAX]; int pos[_MAX][_MAX],col[MAX_POINT],vis[MAX_POINT]; struct DINIC { int first[MAX_POINT],cnt; int next[MAXE],to[MAXE],caps[MAXE]; int deep[MAX_POINT]; DINIC(){cnt = 1;} void add(int x,int y,int f) { next[++cnt] = first[x]; to[cnt] = y; caps[cnt] = f; first[x] = cnt; } void insert(int x,int y,int f) { add(x,y,f); add(y,x,0); } bool BFS() { queue<int> q; memset(deep,0,sizeof(deep)); deep[S] = 1; q.push(S); while(!q.empty()) { int x = q.front(); q.pop(); for(int i = first[x]; i; i = next[i]) if(caps[i] && !deep[to[i]]) { deep[to[i]] = deep[x] + 1; q.push(to[i]); if(to[i] == T) return true; } } return false; } int dfs(int x,int f) { if(x == T) return f; int temp = f; for(int i = first[x]; i; i = next[i]) if(caps[i] && deep[to[i]] == deep[x] + 1 && temp) { int w = dfs(to[i],min(caps[i],temp)); if(!w) deep[to[i]] = 0; caps[i] -= w; caps[i^1] += w; temp -= w; } return f - temp; } }G; int ctt; void DFS(int x,int f) { vis[x] = 1; if(col[x] == f && x != S && x != T)ans[++ctt] = x; for(int i = G.first[x]; i; i = G.next[i]) if(G.caps[i] == f && !vis[G.to[i]])DFS(G.to[i],f); } void solveGraph() { for(int i = 1; i <= m; i++) for(int j = 1; j <= n; j++) { if(s[i][j] == '#') continue; if(!((i + j)&1))G.insert(S,pos[i][j],1),col[pos[i][j]] = 1; else { G.insert(pos[i][j],T,1); continue; } for(int k = 1; k <= 4; k++) { int fx = i + dx[k],fy = j + dy[k]; if(fx < 1 || fy < 1 || fx > m || fy > n) continue; if(s[fx][fy] == '.')G.insert(pos[i][j],pos[fx][fy],1); } } while(G.BFS())G.dfs(S,inf); DFS(S,1);memset(vis,0,sizeof(vis));DFS(T,0); } int main() { scanf("%d%d",&m,&n); for(int i = 1; i <= m; i++) scanf("%s",s[i] + 1); int cnt = 0; for(int i = 1; i <= m; i++) for(int j = 1; j <= n; j++) pos[i][j] = ++cnt; solveGraph(); printf("%d\n",ctt); sort(ans + 1,ans + ctt + 1); for(int i = 1; i <= ctt; i++)printf("%d %d\n",(ans[i] - 1) / n + 1,(ans[i] - 1) % n + 1); return 0; }