• 7.24~7.28


    最近咕咕了很多题目的题解,我来补锅了!!!

    The Great Marathon

    神仙题。。。

    首先预处理两个点的最短路

    然后枚举金牌最后一名和铜牌第一名,就可以确定每位选手能不能获得金银铜

    然后考虑dp

    (dp[i][j][k]) 表示选了 (i) 个人,当前有 (j) 个金,(k) 个银的方案数

    具体实现见代码

    ll f[N][N] ;
    int g[N][N], Min[N], Max[N] ;
    bool gold[N], silver[N], bronze[N] ;
    int n, m, g1, g2, s1, s2 ;
    ll ans ;
    
    signed main() {
    	scanf("%d%d", &n, &m) ;
    	ass(g, 0x3f) ;
    	rep(i, 1, n) g[i][i] = 0 ;
    	rep(i, 1, m) {
    		int a, b, c ; scanf("%d%d%d", &a, &b, &c) ;
    		g[a][b] = g[b][a] = min(g[a][b], c) ;		
    	}
    	rep(k, 1, n) rep(i, 1, n) rep(j, 1, n) chmin(g[i][j], g[i][k] + g[k][j]) ;
    	rep(i, 1, n) {
    		Min[i] = INF ; Max[i] = 0 ;
    		rep(j, 1, n)
    		if (i != j) {
    			g[i][j] = g[i][j] * 60 + i ;
    			chmax(Max[i], g[i][j]) ; chmin(Min[i], g[i][j]) ;
    		}
    	}
    	scanf("%d%d%d%d", &g1, &g2, &s1, &s2) ;
    	ans = 0 ;
    	rep(bst, 1, n) // gold last (ignore the vars' name)
    	rep(wst, 1, n) // bronze first
    	if (wst != bst && Min[bst] < Max[wst]) {
    		rep(i, 1, n) {
    			gold[i] = Min[i] <= Min[bst] ;
    			bronze[i] = Max[i] >= Max[wst] ;
    			silver[i] = false ;
    			rep(j, 1, n) 
    			if (i != j && g[i][j] > Min[bst] && g[i][j] < Max[wst]) {
    				silver[i] = true ;
    				break ;
    			}
    		}
    		gold[bst] = true ; silver[bst] = bronze[bst] = false ;
    		gold[wst] = silver[wst] = false ; bronze[wst] = true ;
    		clr(f) ;
    		f[0][0] = 1 ;
    		rep(k, 1, n)
    		per(i, n, 0)
    		per(j, n, 0)
    		if (f[i][j]) {
    			if (gold[k]) add(f[i + 1][j], f[i][j]) ;
    			if (silver[k]) add(f[i][j + 1], f[i][j]) ;
    			if (!bronze[k]) f[i][j] = 0 ;
    		} 
    		rep(i, g1, g2)
    		rep(j, s1, s2)
    		add(ans, f[i][j]) ;
    	}
    	printf("%lld
    ", ans) ;
    	return 0 ;
    }
    

    Destroying the bus station

    写最小割的人的做法都是假的

    vjudge 上已经有人给出了hack数据

    download

    但是贪心(网络流的实质是贪心)已经被否认,我们只能另寻它法

    显然dp不太可靠,。。。(如果这能就神了)

    虽然 (n<=50),但是我们唯一的方法只有暴力!!!

    上!!!搜索!!!

    怎么搜就不用说了吧(自己看代码去)

    套个迭代加深800ms通过

    为什么搜索能通过?

    1. 当最短路还比较大的话,虽然可删的方案比较多,但我们搜索的层数不是很多
    2. 当最短路变小的时候,虽然层数加深,但是可删的边数会变少,我们距离成功也就越进

    所以这是我们搜索的信心来源

    int n, m, p, highest ;
    int pre[N] ;
    vi e[N] ;
    int road[N][N] ;
    bool del[N] ;
    bool flg ;
    
    void bfs() {
    	queue <int> q ;
    	clr(pre) ; pre[1] = -1 ;
        q.push(1) ;
        while (!q.empty()) {
        	int cur = q.front() ; q.pop() ;
        	rep(i, 0, siz(e[cur]) - 1) {
        		int to = e[cur][i] ;
        		if (!del[to] && !pre[to]) {
        			pre[to] = cur ;
        			q.push(to) ;
    			}
    		}
        }
    }
    
    void dfs(int x) {
        bfs() ;
        if (!pre[n]) {
            flg = 1 ;
            return ;
        }
        int num = 0 ;
        for (int i = n; i != -1; i = pre[i]) road[x][++num] = i ;
        if (num - 1 > p) {
        	flg = 1 ;
        	return ;
    	}
        if(x > highest) return ;
        per(i, num - 1, 2) {
            del[road[x][i]] = 1 ;
            dfs(x + 1) ;
            del[road[x][i]] = 0 ;
        }
    }
    
    void init() {
    	flg = 0 ;
    	rep(i, 1, n) e[i].clear() ;
    }
    
    signed main() {
        while (scanf("%d%d%d", &n, &m, &p) != EOF && n) {
        	init() ;
            rep(i, 1, m) {
    			int u, v ; scanf("%d%d", &u, &v) ;
    			e[u].pb(v) ;
     		}
     		rep(i, 0, n - 2) {
    			highest = i ;
    			clr(del) ;
    			dfs(1) ;
    			if (flg) break ;
    		}
            printf("%d
    ", highest) ;
        }
        return 0 ;
    }
    

    DrawingBlackCrosses

    你大爷的又是状压dp

    没怎么听懂qaq

    大概就是枚举每个黑格子(?)的行和列是否被删然后转移

    献上某神仙的代码(orz)

    #define bitcnt(x) __builtin_popcount(x)
    
    class DrawingBlackCrosses {
    public:
    	int n, m, tot ;
    	int f[N][N], sumx[N], sumy[N] ;
    	bool validx[N], validy[N] ;
    	vii black ;
    	void reduce(int &x) { x += x >> 31 & mod ; }
    	bool check(int msk) {
    		rep(i, 0, n - 1) sumx[i] = 0 ;
    		rep(i, 0, m - 1) sumy[i] = 0 ;
    		rep(i, 0, tot - 1) 
    		if (msk & (1 << i)) {
    			sumx[black[i].fi]++ ;
    			sumy[black[i].se]++ ;
    		}
    		int a = 0, b = 0 ;
    		rep(i, 0, n - 1)
    		if (!a) a = sumx[i] ;
    		else if (sumx[i] && a != sumx[i]) return 0 ;
    		rep(i, 0, m - 1)
    		if (!b) b = sumy[i] ;
    		else if (sumy[i] && b != sumy[i]) return 0 ;
    		return (a == 0 && b == 0 || b - a == n - m) && a * b == bitcnt(msk) ; 
    	}
    	bool check(int S0, int S1) {
    		rep(i, 0, tot - 1)
    		if (S0 & (1 << i))
    		rep(j, 0, tot - 1)
    		if (S1 & (1 << j))
    		if (black[i].fi == black[j].fi || black[i].se == black[j].se) 
    		return 0 ;
    		rep(i, 0, tot - 1)
    		if (S1 & (1 << i))
    		rep(j, i + 1, tot)
    		if (S1 & (1 << j))
    		if (black[i].fi == black[j].fi || black[i].se == black[j].se) 
    		return 0 ;
    		return 1 ;
    	}
    	int count(vector <string> field) {
    		n = siz(field) ;
    		m = siz(field[0]) ;
    		rep(i, 0, n) f[i][0] = 1 ;
    		rep(i, 0, m) f[0][i] = 1 ;
    		rep(i, 1, n)
    		rep(j, 1, m)
    		f[i][j] = mulv(mulv(f[i - 1][j -1], i), j) ;
    		rep(i, 0, n - 1)
    		rep(j, 0, m - 1)
    		if (field[i][j] == 'B') 
    		black.pb(mp(i, j)) ;
    		tot = siz(black) ;
    		int ans = 0 ;
    		rep(msk0, 0, (1 << tot) - 1)
    		 if (check(msk0))
    		 rep(msk1, 0, (1 << tot) - 1)
    		 if (check(msk0, msk1)) {
    		 	clr(validx) ; clr(validy) ;
    		 	rep(i, 0, tot - 1)
    		 	if (msk0 & (1 << i))
    		 	validx[black[i].fi] = 1, validy[black[i].se] = 1 ;
    		 	rep(i, 0, tot - 1)
    		 	if (msk1 & (1 << i))
    		 	validx[black[i].fi] = 1, validy[black[i].se] = 1 ;
    		 	int a = n, b = m ;
    		 	rep(i, 0, n - 1) a -= validx[i] ;
    		 	rep(i, 0, m - 1) b -= validy[i] ;
    		 	int val = f[a][b], step = min(a, b) ;
    		 	rep(i, 1, bitcnt(msk1)) mul(val, step + i) ;
    		 	if (__builtin_parity(msk1)) sub(ans, val) ;
    		 	else add(ans, val) ;
    		 }
    		return ans ;
    	}
    } sol ;
    

    Google Code Jam

    还不错的好题

    应该可以总结一种贪心的策略

    只考虑那些 (0<P_i<1) 的大测试数据

    考虑相邻两个题目优先完成的顺序的排序方式(什么鬼凑活理解一下吧)

    假如是 (i,j),如果 (i) 要在 (j) 前面,那么必须满足:

    [(T_i+T_j)(1-P_j)+T_i(1-P_i)P_j<(T_i+T_j)(1-P_i)+T_j(1-P_j)P_i\ -P_j*T_j-T_i*P_j*P_i<-P_i*T_i-T_j*P_i*P_j\ T_i*P_i(1-P_j)<T_j*P_j(1-P_i)\ T_i*P_i/(1-P_i)<T_j*P_j(1-P_j) ]

    我们就推出了 (i)(j) 之前需要满足的条件

    这样就可以 (dp)

    (dp[i][j][0/1]) 表示我们已经考虑了前 (i) 个题目,当前我们花费了 (j) 分钟所能够达到的最大期望分数/期望时间

    此题卡精度,解决方案:乘大整数, 然后取整 (dp)

    const int base = 1000000 ;
    ll ss[N], sl[N], f[N], p[N], tl[N], ts[N] ;
    int n, t, ord[N] ;
    double pp[N], g[N] ;
    double ans ;
    
    bool cmp(int i, int j) {
        return (tl[i] + tl[j]) * (base - p[j]) * base + tl[i] * p[j] * (base - p[i]) <
               (tl[i] + tl[j]) * (base - p[i]) * base + tl[j] * p[i] * (base - p[j]) ;
    }
    
    void update(int x, ll v1, double v2) {
        if (v1 > f[x] || v1 == f[x] && v2 < g[x]) f[x] = v1, g[x] = v2 ;
    }
    
    signed main() {
        scanf("%d%d", &n, &t) ;
        rep(i, 1, n) {
            scanf("%lld%lld%lld%lld%lf", &ss[i], &sl[i], &ts[i], &tl[i], &pp[i]) ;
            ord[i] = i ;
            p[i] = (int) (pp[i] * base + 0.5) ;
        }
        sort(ord + 1, ord + n + 1, cmp) ;
        rep(_, 1, n) {
            int i = ord[_] ;
            per(j, t, 0) {
                if (j + ts[i] <= t) update(j + ts[i], f[j] + ss[i] * base, g[j] + ts[i]) ;
                if (j + ts[i] + tl[i] <= t)
                update(j + ts[i] + tl[i], f[j] + ss[i] * base + sl[i] * (base - p[i]), 
    					ts[i] + g[j] * pp[i] + (j + tl[i]) * (1 - pp[i])) ;
            }
        }
        ans = g[t] ;
        rep(i, 0, t)
        if (f[i] == f[t] && g[i] < ans)
        ans = g[i];
        printf("%.10lf %.10lf
    ", (double) f[t] / base, ans) ;
        return 0 ;
    }
    

    Galaxy Union

    树的部分直接换根dp

    环two-pointers

    口胡选手没写出来qaq

    RoadsofKingdom

    ntmd 怎么又是状压dp

    树?合并?状压?还蛮好想到的吧(大雾)

    对于一个状态msk,我们考虑子状态 (S_1,S_2=msk-S_1),为了避免重复,可以固定 (u_1 in S_1, v_1 in S_2)

    (S_1=u_1,u_2,...,u_n)
    (S_2=v_1,v_2,...,v_m)
    (f[msk]=f[S_1]*f[S_2]*sumlimits_{i=1}^m(p_{u_1,v_i}*sum_{x in S_2-v_i}(1-p_{u_1,x}))*prod_{i=2}^nprod_{x in S_2}(1-p_{u_i,x}))

    自己理解一下吧。。。。公式是真的 (van♂)

    class RoadsOfKingdom {
    public:
    	int n ;
    	double dp[M], f1[M][N], f2[M][N], prob[N][N] ;
    	bool vis[M] ;
    
    	double dfs(int msk) {
    		if (vis[msk]) return dp[msk] ;
    		int p1 = -1, p2 = -1 ;
    		rep(i, 0, n - 1)
    		if (msk & (1 << i)) {
    			if (p1 == -1) p1 = i ;
    			else if (p2 == -1) { p2 = i ; break ; } 
    		}
    		if (p2 == -1) return 1 ; // endings
    		int Msk = msk ^ (1 << p1) ^ (1 << p2) ;
    		double ans = 0 ;
    		for (int nmsk = Msk;; nmsk = (nmsk - 1) & Msk) { 
    			int msk1 = nmsk | (1 << p1) ;
    			int msk2 = msk ^ msk1 ;
    			double tmp = 1 ;
    			rep(i, 0, n - 1)
    			if (p1 != i && (msk1 & (1 << i))) 
    			tmp *= f1[msk2][i] ;
    			ans += dfs(msk1) * dfs(msk2) * f2[msk2][p1] * tmp ;
    			if (!nmsk) break ;
    		}
    		vis[msk] = 1 ;
    		return dp[msk] = ans ;
    	}
    	double getProbability(vector <string> roads) {
    		n = siz(roads) ;
    		rep(i, 0, n - 1)
    		rep(j, 0, n - 1) 
    		prob[i][j] = (roads[i][j] - '0') / 8.0 ;
    		rep(i, 0, (1 << n) - 1) 
    		rep(j, 0, n - 1) {
    			f1[i][j] = 1 ; 
    			f2[i][j] = 0 ;
    			rep(k, 0, n - 1) 
    			if (i & (1 << k)) {
    				f1[i][j] *= (1 - prob[k][j]) ;
    				f2[i][j] += f1[i ^ (1 << k)][j] * prob[j][k] ;
    			}
    		}
    	//	cout << "???
    " ;
    		return dfs((1 << n) - 1) ;
    	}
    } sol ;
    

    Levko and Sets

    原根是什么qaq

    这题先咕咕

    Roadside Trees

    线段树暴力维护前10小的数然后dp

    #define ls(x) x << 1
    #define rs(x) x << 1 | 1
     
    struct tree {
        int f[N] ;
    	void pushup(int p) { f[p] = max(f[ls(p)], f[rs(p)]) ; }
        void update(int p, int l, int r, int x, int y) {
            if (l == r) {
                f[p] = y ;
                return ;
            }
            int mid = l + r >> 1 ;
            if (x <= mid) update(ls(p), l, mid, x, y) ;
            else update(rs(p), mid + 1, r, x, y) ;
            pushup(p) ;
        }
        int query(int p, int l, int r, int x, int y) {
            if (x <= l && r <= y) return f[p] ;
            int mid = l + r >> 1, ans = 0 ;
            if (x <= mid) ans = max(ans, query(ls(p), l, mid, x, y)) ;
            if (y > mid) ans = max(ans, query(rs(p), mid + 1, r, x, y)) ;
            return ans ;
        }
    };
     
    tree f, g ; // pos, height
    int n, q ;
    int pos[N], height[N], a[N] ;
    set<int> s ;
     
    int main() {
        scanf("%d%d", &n, &q) ;
        int m = delta + 10010 ;
    	while (q--) {
    		int op ; scanf("%d", &op) ;
            if (op == 1) {
            	int p, h ;
            	scanf("%d%d", &p, &h) ; h += delta ;
                s.insert(p) ;
                pos[h] = p ; 
                height[p] = h ;
                per(i,h, h - 9) {
                    if (!pos[i]) continue ;
                    int now = pos[i] ;
                    f.update(1, 1, n, now, 0) ;
                    g.update(1, 1, m, i, 0) ;
                }
                per(i, h, h - 9) {
                    if (!pos[i]) continue ;
                    int now = f.query(1, 1, n, pos[i] + 1, n) + 1 ;
                    f.update(1, 1, n, pos[i], now) ;
                    g.update(1, 1, m, i, now) ;
                }
            } else {
                int k ; scanf("%d", &k) ;
                auto it = s.begin() ;
                int cnt = 0 ;
                while (cnt < k) a[++cnt] = *it, ++it ;
                --it ;
                s.erase(it) ;
                rep(i, 1, cnt) {
                    if (!height[a[i]]) continue ;
                    f.update(1, 1, n, a[i], 0) ;
                    g.update(1, 1, m, height[a[i]], 0) ;
                }
                per(i, cnt - 1, 1) {
                    if (!height[a[i]]) continue ;
                    int now = g.query(1, 1, m, height[a[i]] + 1, m) + 1 ;
                    f.update(1, 1, n, a[i], now) ;
                    g.update(1, 1, m, height[a[i]], now) ;
                }
                pos[height[a[cnt]]] = 0 ;
                height[a[cnt]] = 0 ;
            }
            printf("%d
    ", f.f[1]) ;
            delta-- ;
        }
        return 0 ;
    }
    
    

    Castles

    太水了我tmd都不想写了
    跟subway timing 做法类似

    vi g[N] ;
    int att[N], die[N], rem[N] ;
    int n, ans ;
    
    pii solve(int p, int fa) {
    	vii v ;
    	rep(i, 0, siz(g[p]) - 1) {
    		int to = g[p][i] ;
    		if (to == fa) continue ;
    		v.pb(solve(to, p)) ;
    	}
    	sort(all(v)) ;
    	pii res ;
    	res.se = max(att[p], rem[p] + die[p]) ;
    	res.fi = res.se - die[p] - rem[p] ;
    	per(i, siz(v) - 1, 0) {
    		pii cur = v[i] ;
    		int Rem = res.fi - cur.se ;
    		if (Rem >= 0) res.fi = Rem + cur.fi ;
    		else {
    			res.se -= Rem ;
    			res.fi = cur.fi ; 
    		}
    	}
    	return res ;
    } 
    
    signed main() {
    	int Case = 0 ;
    	while (scanf("%d", &n) != EOF && n) {
    		printf("Case %d: ", ++Case) ;
    		rep(i, 1, n) scanf("%d%d%d", &att[i], &die[i], &rem[i]) ;
    		rep(i, 1, n) g[i].clear() ;
    		rep(i, 1, n - 1) {
    			int x, y ; scanf("%d%d",&x, &y) ;
    			g[x].pb(y) ; g[y].pb(x) ;
    		} 
    		ans = iinf ;
    		rep(i, 1, n) {
    			pii cur = solve(i, -1) ;
    			chmin(ans, cur.se) ;
    		}
    		printf("%d
    ", ans) ;
    	}
    
    	return 0 ;
    }
    

    Painting Graphs with AtcoDeer

    群论。。。

    首先tarjan处理出所有的点双联通分量

    对于一个双联通分量,

    1. 如果边数<点数,可放任何颜色
    2. 边数=点数,有一个环,通过Burnside引理求
    3. 边数>点数,那么有多个环,用组合数求
    int fac[N], inv[N] ;
    int dfn[N], low[N], stk[N] ;
    int n, m, k, tim, top, ans ;
    vi e[N] ;
    set <int> s ;
    
    int C(int n, int k) {
    	return mulv(fac[n], mulv(inv[k], inv[n - k])) ;
    }
    
    int burnside(int n) {
    	int s = 0 ;
    	rep(i, 1, n) add(s, pw(k, __gcd(i, n))) ;
    	mul(s, pw(n, mod - 2)) ;
    	return s ;
    }
    void tarjan(int u) {
    	dfn[u] = low[u] = ++tim ;
    	stk[++top] = u ;
    	rep(i, 0, siz(e[u]) - 1) {
    		int to = e[u][i] ;
    		if (!dfn[to]) {
    			tarjan(to) ;
    			chmin(low[u], low[to]) ;
    			if (low[to] >= dfn[u]) {
    				s.clear() ; int t, nn, mm = 0 ; 
    				do {
    					t = stk[top--] ;
    					s.insert(t) ;
    				} while (t != to) ;	
    				s.insert(u) ;
    				nn = siz(s) ;
    				loop(it, s) 
    				rep(i, 0, siz(e[*it]) - 1) 
    				if (s.count(e[*it][i])) mm++ ;
    				mm /= 2 ;
    				if (mm < nn) mul(ans, k) ;
    				if (nn == mm) mul(ans, burnside(mm)) ;
    				if (nn < mm) mul(ans, C(mm + k - 1, k - 1)) ;
     			}
    		} else {
    			chmin(low[u], dfn[to]) ;
    		}
    	}
    }
    
    signed main() {
    	scanf("%d%d%d", &n, &m, &k) ;
    	rep(i, 1, m) {
    		int x, y ; scanf("%d%d", &x, &y) ;
    		e[x].pb(y) ; e[y].pb(x) ;
    	}
    	fac[0] = 1 ;
    	rep(i, 1, m + k) fac[i] = mulv(fac[i - 1], i) ;
    	inv[m + k] = pw(fac[m + k], mod - 2) ;
    	per(i, m + k, 1) inv[i - 1] = mulv(inv[i], i) ;
    	ans = 1 ;
    	rep(i, 1, n) if (!dfn[i]) tarjan(i) ;
    	printf("%d
    ", ans) ;
    	return 0 ;
    }
    

    TheContest

    二分图匹配

    神仙jt的假人做法,就是塞几个假人什么没怎么听懂qaq

    typedef vector <string> vst ;
    class TheContest {
    public:
    	int vis[N], link[N] ;
    	int g[N][N] ;
    	int fix ;
    	int dfs(int u) {
    		if (u <= fix) return 0 ;
    		rep(v, 0, N - 10) 
    		if (g[u][v] && !vis[v]) {
    			vis[v] = 1 ;
    			if (!~link[v] || dfs(link[v])) {
    				link[v] = u ;
    				link[u] = v ;
    				return 1 ;
    			}
    		}
    		return 0 ;
    	}
    	int ans[N][N], used[N][N], use[N][N] ;
    	int cnt[N] ;
     	vst getSchedule(int n, int m) {
    		int r = max(n, m) ;
    		rep(i, 1, n) {
    			clr(g) ; 
    			rep(j, 1, m)
    			rep(k, 1, r) {
    				if (used[j][k]) continue ;
    				g[j][r + k] = 1 ;
    			}
    			rep(j, m + 1, r)
    			rep(k, 1, r) 
    			if (m - cnt[k] < n - i + 1) 
    			g[j][r + k] = 1 ;
    			vi anss ;
    			rep(j, 1, m) {
    				rep(k, 1, r) 
    				if (g[j][k + r] && !use[i][k]) {
    					bool ok = 1 ;
    					ass(link, -1) ;
    					rep(l, 0, siz(anss) - 1) link[l + 1] = anss[l] + r, 
    					link[anss[l] + r] = l + 1 ;
    					link[j] = k + r, link[k + r] = j ;
    					rep(l, j + 1, r) {
    						clr(vis) ;
    						fix = j ;
    						if (!dfs(l)) { ok = 0 ; break ; } 
    					}
    					if (ok) {
    						use[i][k] = 1 ;
    						anss.pb(k) ;
    						cnt[k]++ ;
    						break ;
    					}
    				}
    				ans[i][j] = anss.back() ;
    				used[j][anss.back()] = 1 ;
    			}
    		}
    		vst res(n, string(m, '0')) ;
    		rep(i, 0, n - 1)
    		rep(j, 0, m - 1) {
    			if (ans[i + 1][j + 1] < 10) res[i][j] = '0' + ans[i + 1][j + 1] ;
    			else if (ans[i + 1][j + 1] < 36) 
    			res[i][j] = 'A' + ans[i + 1][j + 1] - 10 ;
    			else res[i][j] = 'a' + ans[i + 1][j + 1] - 36 ;
    		} 
    		return res ;
    	} 
    } sol ;
    

    Subway Timing

    二分+树形dp

    题解咕咕

    
    int f[N][M], tmp[M] ;
    int n, mid ;
    vii e[N] ;
    
    int isok(int x) {
    	if (x >= -mid && x <= mid) return 1 ;
    	return 0 ;
    }
    
    void dfs(int x, int fa) {
    	rep(i, 0, mid) f[x][i] = -iinf ;
    	f[x][0] = 0 ;
    	rep(i, 0, siz(e[x]) - 1) {
    		int to = e[x][i].fi, w = e[x][i].se ;
    		if (to == fa) continue ;
    		dfs(to, x) ;
    		rep(j, 0, mid) {
    			tmp[j] = f[x][j] ;
    			f[x][j] = -iinf ;
    		}
    		rep(j, 0, mid)
    		if (tmp[j] != -iinf) 
    		rep(k, 0, mid)
    		if (f[to][k] != iinf) {
    			if (isok(j + k - w) && isok(tmp[j] + f[to][k] - w))	
    			chmax(f[x][max(j, k - w)], min(tmp[j], f[to][k] - w)) ;
    			w -= 60 ;
    			if (isok(j + k - w) && isok(tmp[j] + f[to][k] - w))
    			chmax(f[x][max(j, k - w)], min(tmp[j], f[to][k] - w)) ;
    			w += 60 ;
    		}
    	}
    }
    
    bool check(int mid) {
    	dfs(1, 0) ;
    	rep(i, 0, mid) if (f[1][i] > -iinf) return false ;
    	return true ;
    }
    
    signed main() {
    	int Case = 0 ;
    	while (scanf("%d", &n) && n) {
    		rep(i, 1, n) e[i].clear() ;
    		rep(i, 1, n - 1) {
    			int u, v, w ; scanf("%d%d%d", &u, &v, &w) ;
    			w %= 60 ;
    			e[u].pb(mp(v, w)) ;
    			e[v].pb(mp(u, w)) ;
    		}
    		int l = -1, r = 120 ;
    		while (l + 1 < r) { // 二分最小的代价 
    			mid = (l + r) >> 1 ;
    			dfs(1, 0) ;
    			if (check(mid)) l = mid ;
    			else r = mid ;
    		}
    		printf("Case %d: %d
    ", ++Case, r) ;
    	}	
    
    	return 0 ;
    }
    

    My bad

    就是个模拟没什么好说的

    大力枚举然后暴力check

    古老代码

    #include <iostream>
    #include <string>
    #include <string.h>
    #include <stdlib.h>
    using namespace std;
    struct dat_edge {
        int aim, last;
    } edge[201];
    
    int n, m, k, inde[101], coun[101], tmp_coun[101], pl[101], len_edge, num_key, key[300][101];
    char kind[101];
    
    void insert_edge(int x, int y) {
        len_edge++;
        edge[len_edge].aim = y;
        edge[len_edge].last = pl[x];
        pl[x] = len_edge;
    }
    
    void init(int o, string z) {
        int p, i, num;
        string t;
        p = 1;
        z += ' ';
        for (i = 1; i < z.length(); i++)
            if (z[i] == ' ') {
                t = z.substr(p, i - p);
                if (t[0] == 'i')
                    num = 0;
                else
                    num = n;
                if (t.length() == 2)
                    num += t[1] - '0';
                else {
                    num += (t[1] - '0') * 10 + t[2] - '0';
                }
                coun[o]++;
                insert_edge(num, o);
                p = i + 1;
            }
    }
    
    bool solve(int key[], int poi, int sta) {
        int i, p, o, w, tmp, que[101], f[101];
        for (i = 1; i <= n + m + k; i++) {
            f[i] = 0;
        }
        for (i = 1; i <= n; i++) f[i] = key[i];
        for (i = 1; i <= m; i++) {
            if (kind[i] == 'a')
                f[i + n] = 1;
            else
                f[i + n] = 0;
        }
        o = n;
        w = 0;
        for (i = 1; i <= n; i++) que[i] = i;
        while (w < o) {
            w++;
            if (que[w] == poi) {
                if (sta == 2)
                    f[que[w]] = !f[que[w]];
                else
                    f[que[w]] = sta;
            }
            p = pl[que[w]];
            while (p != -1) {
                coun[edge[p].aim]--;
                if (coun[edge[p].aim] == 0) {
                    que[++o] = edge[p].aim;
                }
                tmp = edge[p].aim;
                if (kind[tmp - n] == 'a') {
                    if (f[que[w]] == 0)
                        f[tmp] = 0;
                } else if (kind[tmp - n] == 'o') {
                    if (f[que[w]] == 1)
                        f[tmp] = 1;
                } else if (kind[tmp - n] == 'x') {
                    f[tmp] = f[tmp] ^ f[que[w]];
                } else {
                    f[tmp] = !f[que[w]];
                }
                p = edge[p].last;
            }
        }
        for (i = 1; i <= n + m + k; i++) coun[i] = tmp_coun[i];
        for (i = 1; i <= k; i++) {
            if (f[inde[i] + n] != key[n + i])
                return false;
        }
        return true;
    }
    
    void work(int t) {
        int i, j, p, ans1, ans2, coun_ans;
        bool ok = true;
        for (i = 1; i <= num_key; i++) {
            if (!solve(key[i], -1, -1)) {
                ok = false;
                break;
            }
        }
        if (ok) {
            cout << "Case " << t << ": No faults detected
    ";
            return;
        }
        ans1 = ans2 = coun_ans = 0;
        for (i = 1; i <= m; i++) {
            for (j = 0; j <= 2; j++) {
                ok = true;
                for (p = 1; p <= num_key; p++) {
                    ok = solve(key[p], i + n, j);
                    if (!ok)
                        break;
                }
                if (ok) {
                    ans1 = i;
                    ans2 = j;
                    coun_ans++;
                }
            }
        }
        if (coun_ans != 1) {
            cout << "Case " << t << ": Unable to totally classify the failure
    ";
            return;
        }
        if (ans2 == 2) {
            cout << "Case " << t << ": Gate " << ans1 << " is failing; output inverted
    ";
            return;
        }
        if (ans2 == 0) {
            cout << "Case " << t << ": Gate " << ans1 << " is failing; output stuck at 0
    ";
            return;
        }
        if (ans2 == 1) {
            cout << "Case " << t << ": Gate " << ans1 << " is failing; output stuck at 1
    ";
            return;
        }
    }
    
    int main() {
        int t, i, j;
        string z;
        t = 0;
        while (cin >> n >> m >> k && n + m + k != 0) {
            t++;
            memset(coun, 0, sizeof(coun));
            len_edge = -1;
            for (i = 1; i <= n + m + k; i++) pl[i] = -1;
            for (i = 1; i <= m; i++) {
                cin >> kind[i];
                getline(cin, z);
                init(i + n, z);
            }
            for (i = 1; i <= n + m + k; i++) tmp_coun[i] = coun[i];
            for (i = 1; i <= k; i++) cin >> inde[i];
            cin >> num_key;
            for (i = 1; i <= num_key; i++)
                for (j = 1; j <= n + k; j++) cin >> key[i][j];
            work(t);
        }
        return 0;
    }
    

    The Great Wall Game

    嘿嘿嘿我喜欢网络流

    神仙 (ycs) 用状压 (dp)(f**k it) 秒了此题

    我这个菜鸡只会费用流

    暴力枚举最多32种最终状态

    1. 建立超级源和超级汇
    2. 将所有的目标节点和超级汇连边 ((0,1))
    3. 将超级源和初始节点连边 ((0,1))
    4. 将初始节点和所有目标节点连边 ((dis(i,j),inf))
    5. 跑最小费用最大流
    int n, m, cur, ans, top, s = 31, t = 32 ;
    int head[N], pre[N], x[N], y[N], vis[N], dis[N] ;
    
    struct Edge {
    	int fr, to, nxt, val, len ;	
    } e[M] ;
    
    void add(int a, int b, int c, int d) {
    	e[++top] = (Edge) {a, b, head[a], c, d}  ; head[a] = top ;
    	e[++top] = (Edge) {b, a, head[b], -c, 0} ; head[b] = top ;
    }
    
    void init() {
    	clr(head) ; top = 1 ;
    	cur = 0 ;
    }
    
    int spfa() {
    	queue <int> q ; while (!q.empty()) q.pop() ;
    	ass(dis, 0x3f) ; clr(pre) ;
    	q.push(s) ; dis[s] = 0 ;
    	bool flg = 0 ;
    	while (!q.empty()) {
    		int u = q.front() ; q.pop() ;
    		if (u == t) flg = 1 ;
    		vis[u] = false ;
    		cont(i, u) {
    			int to = e[i].to ;
    			if (!e[i].len) continue ;		
    			if (dis[u] + e[i].val < dis[to]) {
    				dis[to] = dis[u] + e[i].val ;
    				pre[to] = i ;
    				if (!vis[to]) {
    					vis[to] = 1 ;
    					q.push(to) ;
    				}
    			}
    		}
    	}
    	return flg ;
    }
    
    void EK() {
    	while (spfa()) {
    		for (int i = pre[t]; i; i = pre[e[i].fr]) {
    			e[i].len-- ; e[i ^ 1].len++ ;
    			cur += e[i].val ;
    		}
    	}
    	chmin(ans, cur) ;
    }
     
    void horizontal(int l) {
    	init() ;
    	rep(i, 1, n) add(i, t, 0, 1) ;
    	rep(i, 1, n) {
    		add(s, i + n, 0, 1) ;
    		rep(j, 1, n) add(i + n, j, abs(x[i] - l) + abs(y[i] - j), 100) ;
    	}
    	EK() ;
    }
    
    void vertical(int l) {
    	init() ;
    	rep(i, 1, n) add(i, t, 0, 1) ;
    	rep(i, 1, n) {
    		add(s, i + n, 0, 1) ;
    		rep(j, 1, n) add(i + n, j, abs(x[i] - j) + abs(y[i] - l), 100) ;
    	}
    	EK() ;
    }
    
    void diagonal() {
    	init() ;
    	rep(i, 1, n) add(i, t, 0, 1) ;
    	rep(i, 1, n) {
    		add(s, i + n, 0, 1) ;
    		rep(j, 1, n)
    		add(i + n, j, abs(x[i] - j) + abs(y[i] - (n - j + 1)), 100) ;
    	}
    	EK() ;
    	init() ;
    	rep(i, 1, n) add(i, t, 0, 1) ;
    	rep(i, 1, n) {
    		add(s, i + n, 0, 1) ;
    		rep(j, 1, n)
    		add(i + n, j, abs(x[i] - j) + abs(y[i] - j), 100) ;
    	}
    	EK() ;
    }
    
    signed main() {
    	int Case = 0 ;
    	while (scanf("%d", &n) != EOF && n) {
    		rep(i, 1, n) scanf("%d%d", &x[i], &y[i]) ;
    		ans = iinf ;
    		rep(i, 1, n) horizontal(i) ;
    		rep(i, 1, n) vertical(i) ;
    		diagonal() ;
    		printf("Board %d: %d moves required.
    
    ", ++Case, ans) ;
    	}
    	return 0 ;
    }
    

    Battle of the triangle

    二分gg

    Strings of Eternity

    (KMP+dp) 裸题

    (mathsf{Rolling~Hash})(mathsf{Z~Function}) 也都行

    
    char s[N], t[N] ;
    int n, m, k, ans ;
    int fail[N], dp[N] ;
    
    signed main() {
    	scanf("%s%s", s + 1, t + 1) ;
    	k = strlen(s + 1), n = k, m = strlen(t + 1) ; 
    	while (n < m * 2) {
    		rep(i, 1, n) s[n + i] = s[i] ;
    		n *= 2 ;
    	}
    	rep(i, 1, n) s[n + i] = s[i] ; n *= 2 ;
    	fail[0] = -1 ;
    	rep(i, 1, m) {
    		int j = i - 1 ;
    		for (; j && t[fail[j] + 1] != t[i]; j = fail[j]) ;
    		fail[i] = fail[j] + 1 ; 
    	}
    	int j = 0 ;
    	rep(i, 1, n) {
    		for (; ~j && s[i] != t[j + 1]; j = fail[j]) ;
    		j++ ;
    		if (j == m) dp[i] = dp[i - m] + 1, chmax(ans, dp[i]) ;
    	}
    	if (ans >= n / m - 1) ans = -1 ;
    	printf("%d
    ", ans) ;
    	return 0 ;
    }
    
    
  • 相关阅读:
    python中join函数
    python实现反转字符串
    map函数
    python中lambda函数
    python中reduce函数
    python实现斐波那契数列
    迭代器和生成器
    经典算法动态图
    数据中心团队对于液体冷却的应用还需要适应
    物联网正将数据中心推向边缘
  • 原文地址:https://www.cnblogs.com/harryhqg/p/SXBDay2.html
Copyright © 2020-2023  润新知