zoukankan      html  css  js  c++  java
  • 自嗨测试赛1

    Robert 的火车旅行

    线段树合并

    对于不在环上的直接线段树合并统计,对于环上的,第一圈边线段树合并边统计,第二圈统计上上一圈没统计的就行

    Code
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int maxn = 5e5+10;
    int n, k, cnt, top, tot;
    int p[maxn], head[maxn], dep[maxn];
    int rt[maxn], sta[maxn], a[maxn], cc[maxn], ans[maxn];
    bool cir[maxn], vis[maxn];
    struct Edge {
    	int to, nxt;
    }e[maxn<<1];
    struct Node {
    	int ls, rs, siz;
    }t[maxn*25];
    
    int read(int x = 0, bool f = 0, char ch = getchar()) {
    	for(;ch < '0' || ch > '9';ch = getchar()) f = ch=='-';
    	for(;ch >= '0' && ch <= '9';ch = getchar()) x = (x<<3)+(x<<1)+(ch&15);
    	return f ? -x : x;
    }
    
    void add(int x, int y) {
    	e[++cnt] = (Edge){y, head[x]}, head[x] = cnt;
    }
    
    void Insert(int &rt, int l, int r, int v) {
    	if(!rt) rt = ++tot;
    	++t[rt].siz;
    	if(l == r) return;
    	int mid = (l+r)/2;
    	if(v <= mid) Insert(t[rt].ls, l, mid, v);
    	else Insert(t[rt].rs, mid+1, r, v);
    }
    
    int Query(int rt, int l, int r, int x, int y) {
    	if(x <= l && r <= y) return t[rt].siz;
    	int mid = (l+r)/2, ret = 0;
    	if(x <= mid) ret += Query(t[rt].ls, l, mid, x, y);
    	if(y  > mid) ret += Query(t[rt].rs, mid+1, r, x, y);
    	return ret;
    }
    
    int merge(int rt1, int rt2) {
    	if(!rt1 || !rt2) return rt1|rt2;
    	t[rt1].siz += t[rt2].siz;
    	t[rt1].ls = merge(t[rt1].ls, t[rt2].ls);
    	t[rt1].rs = merge(t[rt1].rs, t[rt2].rs);
    	return rt1;
    }
    
    void dfs(int x) {
    	vis[x] = 1;
    	for(int i = head[x];i;i = e[i].nxt) {
    		int y = e[i].to;
    		if(cir[y]) continue;
    		dep[y] = dep[x]+1;
    		dfs(y);
    		rt[x] = merge(rt[x], rt[y]);
    	}
    	Insert(rt[x], 1, n, dep[x]);
    	ans[x] = Query(rt[x], 1, n, dep[x], dep[x]+k);
    }
    
    int main() {
    	freopen("robert.in","r",stdin);
    	freopen("robert.out","w",stdout);
    	n = read(), k = read();
    	for(int i = 1;i <= n; ++i) add(p[i]=read(), i);
    	for(int i = 1;i <= n; ++i) {
    		if(vis[i]) continue;
    		int x = i;
    		sta[++top] = x, vis[x] = 1;
    		while(!vis[p[x]]) sta[++top] = x = p[x], vis[x] = 1;
    		int st = p[x], c = 0;
    		do {
    			x = sta[top--];
    			cir[x] = 1, dep[x] = ++c, a[c] = x;
    		} while(x != st);
    		int now = 0;
    		for(int j = c;j >= 1; --j) {
    			dfs(x=a[j]);
    			now = merge(rt[x], now);
    			ans[x] = Query(now, 1, n, dep[x], dep[x]+k);
    			if(k >= c) ans[x] -= Query(now, 1, n, dep[x], dep[x]+k-c);
    		}
    		for(int j = c;j >= 1; --j) {
    			x = a[j];
    			if(k >= (c-j+1)) ans[x] += Query(now, 1, n, 1, 1+k-(c-j+1));
    		}
    	}
    	for(int i = 1;i <= n; ++i) printf("%d
    ", ans[i]);
    	return 0;
    }
    
    

    钻石教练老姚的神仙LIS

    网络流

    • 第一问 n^2 dp

    • 第二问对每个数,拆出、入点,出点向入点连1流量边,根据dp值的转移,出点连向入点,然后s连向所有dp为1的点的入点有1流量边,所有dp为len的点的出点连向t有1流量的边,直接最大流

    • 第三问对于s向1,1向1+n,n向n+n,n+n向t的边流量改为inf即可

    注意特判只有一个数的的情况,ans=1,这一个数不要和s,t都有inf边

    Code
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int maxn = 2e3+10;
    const int maxm = 3e6+10;
    const int inf = 1e9;
    int s, t, n, cnt, len, a[maxn], head[maxn], f[maxn];
    int cur[maxn], dep[maxn];
    struct Edge {
    	int to, nxt, flow;
    }e[maxm];
    
    void add(int x, int y, int flow) {
    	e[++cnt] = (Edge){y, head[x], flow}, head[x] = cnt;
    	e[++cnt] = (Edge){x, head[y], 0}, head[y] = cnt;
    }
    
    bool bfs() {
    	queue <int> q;
    	memset(cur, 0, sizeof cur);
    	memset(dep, 0, sizeof dep);
    	dep[s] = 1, cur[s] = head[s], q.push(s);
    	while(!q.empty()) {
    		int x = q.front(); q.pop();
    		for(int i = head[x];i;i = e[i].nxt) {
    			int y = e[i].to;
    			if(e[i].flow && !dep[y]) {
    				dep[y] = dep[x]+1;
    				cur[y] = head[y];
    				if(y == t) return 1;
    				q.push(y);
    			}
    		}
    	}
    	return 0;
    }
    
    int dinic(int x, int flow) {
    	if(x == t) return flow;
    	int rest = flow;
    	for(int i = cur[x];i && rest;i = e[i].nxt) {
    		cur[x] = i;
    		int y = e[i].to;
    		if(e[i].flow && dep[y] == dep[x]+1) {
    			int tmp = dinic(y, min(rest, e[i].flow));
    			rest -= tmp;
    			e[i].flow -= tmp;
    			e[i^1].flow += tmp;
    		}
    	}
    	return flow-rest;
    }
    
    void Q1() {
    	for(int i = 1;i <= n; ++i) {
    		f[i] = 1;
    		for(int j = 1;j < i; ++j) {
    			if(a[j] <= a[i]) f[i] = max(f[i], f[j]+1);
    		}
    		len = max(len, f[i]);
    	}
    	printf("%d
    ", len);
    }
    
    void Add() {
    	memset(head, 0, sizeof head), cnt = 1;
    	for(int i = 1;i <= n; ++i) {
    		add(i, n+i, 1);
    		if(f[i] == 1) add(s, i, 1);
    		if(f[i] == len) add(i+n, t, 1);
    	}
    	for(int i = 1;i <= n; ++i) {
    		for(int j = 1;j < i; ++j) {
    			if(a[j] <= a[i] && f[i] == f[j]+1) add(j+n, i, 1);
    		}
    	}
    }
    
    void Q2() {
    	Add();
    	int ans = 0;
    	while(bfs()) ans += dinic(s, inf);
    	printf("%d
    ", ans);
    }
    
    void Q3() {
    	Add();
    	add(1, 1+n, inf);
    	add(n, n+n, inf);
    	if(f[1] == 1) add(s, 1, inf);
    	if(f[n] == len && n > 1) add(n+n, t, inf);
    	int ans = 0;
    	while(bfs()) ans += dinic(s, inf);
    	printf("%d
    ", ans);
    }
    
    int main() {
    	scanf("%d", &n), s = n*2+1, t = n*2+2;
    	for(int i = 1;i <= n; ++i) scanf("%d", &a[i]);
    	Q1(), Q2(), Q3();
    	return 0;
    }
    

    组合空间

    子集反演,高维前缀和

    f[s]表示只有状态s表示的位置未被覆盖

    g[s]表示至少状态s表示的位置未被覆盖

    那么ans=f[0]

    子集反演 (f[S]=sum_{Ssubseteq T}(-1)^{left | T ight|-left | S ight|}g[T])

    高维前缀和求出num[s]表示s表示的位置为0的集合个数

    (g[s]=2^{num[s]}-1),其他的都不选,这num[s]个选不选都行,但除去都不选的。

    Code
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int maxn = 1<<22|10;
    const int mod = 1e9+7;
    int n, m, maxs, ans, pw[(int)1e6+10], c[maxn];
    
    int read(int x = 0, bool f = 0, char ch = getchar()) {
    	for(;ch < '0' || ch > '9';ch = getchar()) f = ch == '-';
    	for(;ch >= '0' && ch <= '9';ch = getchar()) x = (x<<3)+(x<<1)+(ch&15);
    	return f ? -x : x;
    }
    
    int main() {
    	freopen("longdie.in","r",stdin);
    	freopen("longdie.out","w",stdout);
    	n = read(), m = read(), maxs = (1<<n)-1;
    	pw[0] = 1;
    	for(int i = 1;i <= m; ++i) pw[i] = pw[i-1]*2%mod;
    	for(int i = 1;i <= m; ++i) {
    		int k = read(), S = maxs;
    		for(int j = 1;j <= k; ++j) S ^= (1<<(read()-1));
    		++c[S];
    	}
    	for(int i = 1;i <= n; ++i) {
    		for(int j = 0;j <= maxs; ++j) {
    			if(j&(1<<(i-1))) c[j^(1<<(i-1))] += c[j];
    		}
    	}
    	for(int i = 0;i <= maxs; ++i) {
    		int g = pw[c[i]]-1;
    		int cc = 0, x = i;
    		for(;x;x -= (x&-x)) ++cc;
    		(ans += (cc&1) ? mod-g : g) %= mod;
    	}
    	printf("%d
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    [代码]codeforces 150c Smart Cheater
    [存档]Young Tableau
    [转载][毁童年]种太阳
    [转载]教练,我也想再要一个同桌
    静夜
    CodeProject每日精选: Applications
    设计模式 装饰模式(Decorator) 精选经验合集
    槟榔味儿办公室
    盗不盗非常盗
    月末之周末
  • 原文地址:https://www.cnblogs.com/Lour688/p/14508166.html
Copyright © 2011-2022 走看看