• CF1408


    CF1408

    那个博客搭好遥遥无期。

    A:

    直接做就行了,我没智力还写 (dp)

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 110
    int n;
    int p[MAXN][3];
    bool f[MAXN][3];
    int pre[MAXN][3];
    int ans[MAXN];
    void work()
    {
    	scanf("%d",&n);
    	for(int j = 0;j < 3;++j)for(int i = 1;i <= n;++i)scanf("%d",&p[i][j]);
    	for(int v = 0;v < 3;++v)
    	{
    		memset(f,0,sizeof(f));
    		f[1][v] = true;
    		for(int i = 2;i <= n;++i)
    		{
    			for(int y = 0;y < 3;++y)
    			{
    				for(int x = 0;x < 3;++x)
    				{
    					if(p[i - 1][x] != p[i][y] && f[i - 1][x])
    					{
    						f[i][y] = true;
    						pre[i][y] = x;
    						break;
    					}
    				}
    			}
    		}
    		bool tag = false;
    		for(int i = 0;i < 3;++i)
    		{
    			if(f[n][i] && p[n][i] != p[1][v])
    			{
    				for(int k = n,cur = i;k >= 1;--k)
    				{
    					ans[k] = p[k][cur];
    					cur = pre[k][cur];
    				}
    				for(int k = 1;k <= n;++k)printf("%d ",ans[k]);puts("");
    				tag = true;
    				break;
    			}
    		}
    		if(tag)break;
    	}
    	return;
    }
    int main()
    {
    	int testcases;
    	scanf("%d",&testcases);
    	while(testcases--)work();
    	return 0;
    }
    

    B:

    还挺有意思的,就是从左往右数如果颜色达到(k)了就把剩下的拿出去再一样做,统计颜色段数算一算。

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 110
    int n,k;
    int a[MAXN];
    void work()
    {
    	scanf("%d%d",&n,&k);
    	for(int i = 1;i <= n;++i)scanf("%d",&a[i]);
    	int cnt = 0;
    	for(int i = 1;i < n;++i)if(a[i] != a[i + 1])++cnt;
    	if(cnt == 0)puts("1");
    	else if(k == 1)puts("-1");
    	else
    	{
    		++cnt;
    		int ans = 0;
    		while(cnt > 0)
    		{
    			++ans;
    			cnt -= k;
    			if(cnt <= 0)break;
    			++cnt;
    		}
    		cout << ans << endl;
    	}
    	
    	return;
    }
    int main()
    {
    	int testcases;
    	scanf("%d",&testcases);
    	while(testcases--)work();
    	return 0;
    }
    

    C:

    算到每个位置两人的速度和时间,这样即可得知在哪段相遇,然后就能算了。

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 100010
    int n,l;
    int a[MAXN];
    double ta[MAXN],tb[MAXN];
    int va[MAXN],vb[MAXN];
    void work()
    {
    	scanf("%d%d",&n,&l);
    	for(int i = 1;i <= n;++i)scanf("%d",&a[i]);
    	a[n + 1] = l;
    	ta[0] = 0;va[0] = 1;
    	for(int i = 1;i <= n + 1;++i)
    	{
    		va[i] = va[i - 1] + 1;
    		ta[i] = double(a[i] - a[i - 1]) / va[i - 1] + ta[i - 1];
    	}
    	tb[n + 1] = 0;vb[n + 1] = 1;
    	for(int i = n;i >= 0;--i)
    	{
    		vb[i] = vb[i + 1] + 1;
    		tb[i] = double(a[i + 1] - a[i]) / vb[i + 1] + tb[i + 1];
    	}
    	for(int i = 1;i <= n;++i)
    	{
    		if(fabs(ta[i] - tb[i]) <= 1e-6)
    		{
    			printf("%.20lf
    ",ta[i]);
    			return;
    		}
    	}
    	int pos = -1;
    	for(int i = 0;i <= n;++i)
    	{
    		if(ta[i] <= tb[i] && ta[i + 1] >= tb[i + 1])
    		{
    			pos = i;
    			break;
    		}
    	}
    	printf("%.20lf
    ",(a[pos + 1] - a[pos] + ta[pos] * va[pos] + tb[pos + 1] * vb[pos + 1]) / (va[pos] + vb[pos + 1]));
    	return;
    }
    int main()
    {
    	int testcases;
    	scanf("%d",&testcases);
    	while(testcases--)work();
    	return 0;
    }
    

    D:

    对每个向上走的长度记录 (l[i]) 表示要向右走多少才行,然后会发现可以前缀最大值做。

    #include<bits/stdc++.h>
    using namespace std; 
    int n,m;
    #define MAXN 2010
    #define INF 0x3f3f3f3f
    int a[MAXN],b[MAXN],c[MAXN],d[MAXN];
    struct move
    {
    	int u,r;
    }s[MAXN];
    int up[1000010];
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i = 1;i <= n;++i)scanf("%d%d",&a[i],&b[i]);
    	for(int i = 1;i <= m;++i)scanf("%d%d",&c[i],&d[i]);
    	for(int i = 1;i <= n;++i)
    	{
    		for(int j = 1;j <= m;++j)
    		{
    			if(c[j] >= a[i] && d[j] >= b[i])
    			{
    				up[c[j] - a[i]] = max(up[c[j] - a[i]],d[j] - b[i] + 1);
    			}
    		}
    	}
    	for(int i = 1000000;i >= 0;--i)
    	{
    		up[i] = max(up[i],up[i + 1]);
    	}
    	int ans = 0x3f3f3f3f;
    	for(int i = 0;i <= 1000001;++i)
    	{
    		ans = min(ans,i + up[i]);
    	}
    	cout << ans << endl;
    	return 0;
    }
    

    E:

    把团内的每个点向团所代表的点连边,然后会发现没有 (rainbow) 等价于这个图没有环。

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    #define MAXN 100010
    int a[MAXN],b[MAXN];
    namespace KRU
    {
    	struct edge{int u,v,w;}e[MAXN << 1];
    	int edgenum = 0;
    	void add(int a,int b,int w){e[++edgenum] = (edge){a,b,w};return;}
    	bool cmp(edge a,edge b){return a.w > b.w;}
    	int f[MAXN << 1];
    	int find(int x){return (f[x] == x ? x : f[x] = find(f[x]));}
    	long long kruskal()
    	{
    		long long ans = 0;
    		sort(e + 1,e + 1 + edgenum,cmp);
    		for(int i = 1;i <= n + m;++i)f[i] = i;
    		for(int i = 1;i <= edgenum;++i)
    		{
    			int p = find(e[i].u),q = find(e[i].v);
    			if(p == q)continue;
    			ans += e[i].w;
    			f[p] = q;
    		}
    		return ans;
    	}
    }
    int main()
    {
    	scanf("%d%d",&m,&n);
    	for(int i = 1;i <= m;++i)scanf("%d",&a[i]);
    	for(int i = 1;i <= n;++i)scanf("%d",&b[i]);
    	long long ans = 0;
    	for(int i = 1;i <= m;++i)
    	{
    		int s;scanf("%d",&s);
    		int v;
    		for(int k = 1;k <= s;++k)
    		{
    			scanf("%d",&v);
    			KRU::add(i + n,v,a[i] + b[v]);//cout << " : " << i << " " << v << " " << a[i] << " " << b[v] << " " << a[i] + b[v] << endl;
    			ans += a[i] + b[v];
    		}
    	}
    	ans -= KRU::kruskal();
    	cout << ans << endl;
    	return 0;
    }
    

    F:

    发现可以分治让 (2^n) 长度的区间变成一个数,那么就对 ([1,l])([n-l+1,n]) 都做一遍就行了。

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    vector< pair<int,int> > ans;
    void solve(int l,int r)
    {
    	if(l == r)return;
    	int mid = (l + r) >> 1;
    	solve(l,mid);solve(mid + 1,r);
    	for(int i = l;i <= mid;++i)ans.push_back(make_pair(i,mid + 1 + i - l));
    	return;
    }
    int main()
    {
    	cin >> n;
    	int l = 1;
    	while(l * 2 <= n)l = l * 2;
    	solve(1,l);solve(n - l + 1,n);
    	cout << ans.size() << endl;
    	for(int i = 0;i < ans.size();++i)printf("%d %d
    ",ans[i].first,ans[i].second);
    	return 0;
    }	
    

    G:

    团内边小于团之间的边,一个团可以增加一,连接两个连通块就卷积,相当于树形 (dp)(O(n^2))

    #include<bits/stdc++.h>
    using namespace std;
    #define MOD 998244353
    inline int read()
    {
    	int res = 0;
    	char c = getchar();
    	while(!isdigit(c))c = getchar();
    	while(isdigit(c))
    	{
    		res = (res << 1) + (res << 3) + c - '0';
    		c = getchar();
    	}
    	return res;
    }
    int n;
    #define MAXN 1510
    struct edge
    {
    	int u,v,w;
    }es[MAXN * MAXN];
    int en = 0;
    int f[MAXN];
    int ecnt[MAXN];
    int siz[MAXN];
    int find(int x){return (x == f[x] ? x : f[x] = find(f[x]));}
    bool cmp(edge a,edge b){return a.w < b.w;}
    int dp[MAXN][MAXN];
    int g[MAXN];
    void merge(int a,int b)
    {
    	for(int i = 1;i <= siz[a] + siz[b];++i)g[i] = 0;
    	for(int i = 1;i <= siz[a];++i)
    		for(int j = 1;j <= siz[b];++j)
    			g[i + j] = (g[i + j] + 1ll * dp[a][i] * dp[b][j] % MOD) % MOD;
    	for(int i = 1;i <= siz[a] + siz[b];++i)dp[a][i] = g[i];
    	return;
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i = 1;i <= n;++i)f[i] = i,siz[i] = 1;
    	for(int i = 1;i <= n;++i)for(int j = 1;j <= n;++j)es[++en] = (edge){i,j,read()};
    	sort(es + 1,es + 1 + en,cmp);
    	for(int i = 1;i <= en;++i)
    	{
    		int p = find(es[i].u),q = find(es[i].v);
    		if(p == q)++ecnt[p];
    		else
    		{
    			if(siz[p] < siz[q])swap(p,q);
    			merge(p,q);
    			f[q] = p;
    			siz[p] += siz[q];
    			ecnt[p] += ecnt[q] + 1;
    		}
    		if(ecnt[p] == siz[p] * siz[p])dp[p][1] = 1;
    	}
    	int root = find(1);
    	for(int i = 1;i <= n;++i)printf("%d ",dp[root][i]);
    	return 0;
    }
    

    H:

    设零的个数为 (z) ,则答案不超过 (lfloorfrac z2 floor) ,那么将序列划为两半 (L)(R) ,满足对于 (xin L) 右边有大于 (lfloorfrac z2 floor)(0)(R) 同理,那么可以发现每种颜色只有 (L) 中最右边的和 (R) 中最左边的有用。那么可以网络流,(S) 连颜色,(L) 中每个点往左连,(R) 中每个点往右连,颜色连两个有用的点,零连 (T) ,分析一下,如果一个颜色不割,那么他的前缀零后缀零一定都被割了,那最后一定是割了前缀零,后缀零,还有不是包含在前缀后缀的,于是扫描线加线段树统计。

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    #define MAXN 500010
    int a[MAXN];
    int cnt0;
    struct match{int l,r;}ma[MAXN];
    int sum0l[MAXN],sum0r[MAXN];
    struct node
    {
    	int lc,rc;
    	int minv,tag;
    }t[MAXN << 1];
    int ptr = 0;
    int newnode(){return ++ptr;}
    int root;
    #define mid ((l + r) >> 1)
    void build(int &rt,int l,int r)
    {
    	rt = newnode();
    	if(l == r){t[rt].minv = sum0r[l] + n;return;}
    	build(t[rt].lc,l,mid);
    	build(t[rt].rc,mid + 1,r);
    	t[rt].minv = min(t[t[rt].lc].minv,t[t[rt].rc].minv);
    	return;
    }
    void pushdown(int rt)
    {
    	t[t[rt].lc].minv += t[rt].tag;t[t[rt].lc].tag += t[rt].tag;
    	t[t[rt].rc].minv += t[rt].tag;t[t[rt].rc].tag += t[rt].tag;
    	t[rt].tag = 0;
    	return;
    }
    void add(int rt,int L,int R,int v,int l,int r)
    {
    	if(L <= l && r <= R)
    	{
    		t[rt].minv += v;
    		t[rt].tag += v;
    		return;
    	}
    	pushdown(rt);
    	if(L <= mid)add(t[rt].lc,L,R,v,l,mid);
    	if(R > mid)add(t[rt].rc,L,R,v,mid + 1,r);
    	t[rt].minv = min(t[t[rt].lc].minv,t[t[rt].rc].minv);
    	return;
    }
    int query(int rt,int L,int R,int l,int r)
    {
    	if(L <= l && r <= R)return t[rt].minv;
    	int res = 0x3f3f3f3f;
    	if(L <= mid)res = min(res,query(t[rt].lc,L,R,l,mid));
    	if(R > mid)res = min(res,query(t[rt].rc,L,R,mid + 1,r));
    	return res;
    }
    vector<int> seg[MAXN];
    void work()
    {
    	scanf("%d",&n);
    	for(int i = 1;i <= n;++i)scanf("%d",&a[i]);
    	cnt0 = 0;
    	for(int i = 1;i <= n;++i)cnt0 += (a[i] == 0);
    	int s = (cnt0 + 1) / 2;
    	for(int i = 1;i <= n;++i)ma[i].l = 0,ma[i].r = n + 1;
    	sum0l[0] = sum0r[n + 1] = 0;
    	for(int i = 1;i <= n;++i)sum0l[i] = sum0l[i - 1] + (a[i] == 0);
    	for(int i = n;i >= 1;--i)sum0r[i] = sum0r[i + 1] + (a[i] == 0);
    	int bor;
    	for(int i = 1,c0 = 0;i <= n;++i)
    	{
    		if(a[i] == 0)++c0;
    		if(c0 == s){bor = i;break;}
    	}
    	for(int i = bor;i >= 1;--i)if(a[i] && ma[a[i]].l == 0)ma[a[i]].l = i;
    	for(int i = bor;i <= n;++i)if(a[i] && ma[a[i]].r == n + 1)ma[a[i]].r = i;
    	for(int i = 0;i <= n + 1;++i)seg[i].clear();
    	for(int i = 1;i <= n;++i)seg[ma[i].l].push_back(ma[i].r);
    	ptr = 0;
    	build(root,bor,n + 1);
    	int ans = 0x3f3f3f3f;
    	for(int l = 0;l <= bor;++l)
    	{
    		for(vector<int>::iterator it = seg[l].begin();it != seg[l].end();++it)add(root,bor,*it,-1,bor,n + 1);
    		ans = min(ans,query(root,bor,n + 1,bor,n + 1) + sum0l[l]);
    	}
    	printf("%d
    ",min(ans,cnt0 / 2));
    	for(int i = 1;i <= ptr;++i)t[i].lc = t[i].rc = t[i].minv = t[i].tag = 0;
    	return;
    }
    int main()
    {
    	int testcases = 0;
    	scanf("%d",&testcases);
    	while(testcases--)work();
    	return 0;
    }
    

    I:

    咕咕咕

  • 相关阅读:
    非递归遍历二叉树Java
    【滴滴实习】滴滴2023届产研秋招储备实习生正在火热招募中🔥
    c++从office word的xml源文本文件中提取空行后的首个段落
    自建脚本安装docker
    银河麒麟安装软件失败,可使用命令行安装
    Fiddler+Proxifier抓pc应用包(c/s架构)
    11. Spring高级AOP概念
    10. Spring高级IOC的深入剖析
    12. Spring高级注解驱动AOP开发入门
    9. Spring高级注解驱动开发入门
  • 原文地址:https://www.cnblogs.com/wjh15101051/p/13782818.html
Copyright © 2020-2023  润新知