首页 > 其他分享 >8.27训练赛(2018-2019, ICPC, Asia Yokohama Regional Contest 2018,gym102082)

8.27训练赛(2018-2019, ICPC, Asia Yokohama Regional Contest 2018,gym102082)

时间:2022-08-27 22:00:14浏览次数:74  
标签:Contest int gym102082 nxt2 nxt1 2018 ans col dis

B

一开始开题的时候想假了,以为用map存差的结果贪心就行了,实际上是一个比较妙的dp,用到了一个结论:两项就唯一确定一个等差数列。
设\(f[i,j]\)表示最后两个数选了\(a_i\),\(a_j\)就可以定一个等差数列了,这就很优美地解决了公差没办法定义在状态里面的问题。
把序列排序一下,则转移点是有单调性的,维护一个变量来转移就行了
复杂度\(O(n^2)\)

#include<bits/stdc++.h>
using namespace std;

int a[5050], n;
int f[5050][5050];

int main() {
    cin>>n;
    for(int i = 1; i <= n; ++i) cin >> a[i];
    sort(a+1, a+n+1);
    int ans = 2;
    for(int i = 1; i <= n; ++i) {
        int cur = i;
        for(int j = i + 1; j <= n; ++j) {
            while(cur > 1 && a[cur] > a[i] - (a[j] - a[i])) --cur;
            if(a[i]-a[cur] == a[j] - a[i]) f[i][j] = max(f[i][j], f[cur][i] + 1); 
            else f[i][j] = max(f[i][j], 2);
            ans = max(ans, f[i][j]);
        }
    }
    cout << ans;
}

D

dp
对每个位置处理出0和1下一次出现的地方,然后位置\((i,j)\)可以转移到\((nxt1[i][0],nxt2[j][0])\)或者对应的\((nxt1[i][1],nxt2[j][1])\)
注意边界情况就好。实现的话是记忆化搜索比较方便(毕竟要输出方案)

#include<bits/stdc++.h>
using namespace std;

const int N = 5010;

int ans[N], tot;
int n, m, nxt1[N][2], nxt2[N][2], f[N][N], vis[N][N];
char a[N], b[N];

int dfs(int x, int y) {
   // printf("%d %d\n", x, y);
    if(x == n+1 && y == m+1) return 0;
    if(f[x][y]) return f[x][y];
    int c0 = dfs(nxt1[x][0], nxt2[y][0]), c1 = dfs(nxt1[x][1], nxt2[y][1]);
    if(c0 <= c1) vis[x][y] = -1;
    else vis[x][y] = 1;
    return f[x][y] = min(c0, c1) + 1;
}

void print(int x, int y) {
    if(x == n+1 && y == m+1) return;
    int flag = vis[x][y] > 0;
    ans[++tot] = flag;
    print(nxt1[x][flag], nxt2[y][flag]);
}

int main() {
    scanf("%s", a + 1);
    scanf("%s", b + 1);
    n = strlen(a+1);
    m = strlen(b+1);
    int c0 = n+1, c1 = n+1;
    nxt1[n+1][0] = nxt1[n+1][1] = n+1;
    for(int i = n; i >= 0; --i) {
        nxt1[i][0] = c0;
        nxt1[i][1] = c1;
        if(a[i] - '0') c1 = i;
        else c0 = i;
    }
    c0 = m+1, c1 = m+1;
    nxt2[m+1][0] = nxt2[m+1][1] = m+1;
    for(int i = m; i >= 0; --i) {
        nxt2[i][0] = c0;
        nxt2[i][1] = c1;
        if(b[i] - '0') c1 = i;
        else c0 = i;
    }
    dfs(0, 0);
    print(0, 0);
    for(int i = 1; i <= tot; ++i) printf("%d", ans[i]);
}

G

经典套路题了
有一个(可能是众所周知)的结论,把一个序列通过冒泡排序排序成有序的需要的次数是\(\frac{n\times (n-1)}{2}-\sum \text{逆序对数}\)(每个逆序对都一定要和它经过一次)。
考虑最终的合法序列,这个数要么在左边单增要么在右边单减(就是要么往左挪要么往右挪),根据上面的结论,每个数被交换的次数其实就是顺序的i-逆序对和倒序的i-逆序对取个min

#include<bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;

int c[N], n, a[N], b[N];
long long ans;

#define lowbit(i) (i&-i)
void add(int x, int v) {
    for(int i = x; i < N; i += lowbit(i)) c[i] += v;
}
int query(int x) {
    int ans = 0;
    for(int i = x; i; i -= lowbit(i)) ans += c[i];
    return ans;
}

int main() {
    cin >> n;
    for(int i = 1; i <= n; ++i) cin >> a[i];
    for(int i = 1; i <= n; ++i) {
        add(a[i], 1);
        b[i] = i - query(a[i]);
    }
    for(int i = 1; i < N; ++i) c[i] = 0;
    for(int i = n; i; --i) {
        add(a[i] ,1);
        ans += 1ll*min(b[i], n-i+1 - query(a[i]));
    }
    printf("%lld\n", ans);
}

J

画图手玩出的结论,学长说是经典结论。
包含某些点的生成树就是这些对应的点按照dfs序排序后相邻的距离和加上首尾的距离/2。
具体而言,画个图然后往dfs序方向想一下可以在不经意间发现这个细节,如果我们把同颜色点按照dfn排序,那么\(\frac{dis(1,n)+\sum dis(i,i+1)}{2}\)就是答案。
考虑维护他的操作,拿一个set当平衡树使就好,记\(l,r\)是前驱和后继,加上对答案的贡献就是\(-dis(l, r) + dis(l, x) + dis(x, r)\),改颜色就当删除和重新加入,贡献反过来就好

#include <bits/stdc++.h>
using namespace std;

const int N = 100010;
typedef long long ll;

ll ans[N];
int n, m;
int dep[N], siz[N], top[N], fa[N], col[N], vis[N], dfn[N], tot;
int cnt, head[N];
struct edge {int to, nxt;} e[N << 1];
struct node {
    int x, dfn;
    bool operator < (const node &a) const {
        return dfn < a.dfn;
    }
};
set<node>s[N];
void ins(int u, int v) {
	e[++cnt] = (edge) {v, head[u]};
	head[u] = cnt;
}

void dfs1(int u) {
	siz[u] = 1;
	for(int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if(v == fa[u]) continue;
		dep[v] = dep[u] + 1;
		fa[v] = u;
		dfs1(v);
		siz[u] += siz[v];
	}
}

void dfs2(int u, int topf) {
	dfn[u] = ++tot; top[u] = topf; int k = 0;
	for(int i = head[u]; i; i = e[i].nxt) {
		if(e[i].to == fa[u]) continue;
		if(siz[e[i].to] > siz[k]) k = e[i].to;
	}
	if(!k) return; dfs2(k, topf);
	for(int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to; if(v == fa[u]) continue;
		if(v != k) dfs2(v, v);
	}
}

int lca(int x, int y) {
	while(top[x] != top[y]) {
		if(dep[top[x]] < dep[top[y]]) swap(x, y);
		x = fa[top[x]];
	}
	if(dep[x] < dep[y]) return x;
	return y;
}

int dis(int x, int y) {
    int LCA = lca(x, y);
    return dep[x] + dep[y] - 2*dep[LCA];
}

void add(int x) {
	s[col[x]].insert({x, dfn[x]});
    auto it = s[col[x]].find({x, dfn[x]});
    int l = 0, r = 0;
    ++it;
    if(it != s[col[x]].end()) r = (*it).x;
    --it;
    if(it != s[col[x]].begin()) {
        --it;
        l = (*it).x;
    }
    if(l && r) ans[col[x]] += -dis(l, r) + dis(l, x) + dis(x, r);
    else if(l) ans[col[x]] += dis(l, x);
    else if(r) ans[col[x]] += dis(r, x);
}

void del(int x) {
    auto it = s[col[x]].find({x, dfn[x]});
    int l = 0, r = 0;
    ++it;
    if(it != s[col[x]].end()) r = (*it).x;
    --it;
    if(it != s[col[x]].begin()) {
        --it;
        l = (*it).x;
    }
    if(l && r) ans[col[x]] -= -dis(l, r) + dis(l, x) + dis(x, r);
    else if(l) ans[col[x]] -= dis(l, x);
    else if(r) ans[col[x]] -= dis(r, x);
    s[col[x]].erase(s[col[x]].find({x, dfn[x]}));
}

int Q1(int x) {
    int l = (*s[x].begin()).x, r = (*(--s[x].end())).x;
    return dis(l, r);
}

int main() {
//	freopen("1.in","r",stdin);
	cin >> n;
	for(int i = 1, u, v; i < n; ++i) {
		scanf("%d%d", &u, &v);
		ins(u, v), ins(v, u);
	}
	dfs1(1); dfs2(1,1);
    for(int i = 1; i <= n; ++i) scanf("%d", &col[i]), add(i);
    cin >> m;
    while(m--) {
        char c[3];
        int x, y;
        scanf("%s%d", c, &x);
        if(c[0] == 'U') {
            scanf("%d", &y);
            del(x);
            col[x] = y;
            add(x);
        } else {
        	if(s[x].empty()) puts("-1");
            else printf("%lld\n", 1ll*(ans[x] + Q1(x))/2LL);
        }
    }
	return 0;
}

K

简单贪心,每个位置放剩下的第一个比自己大的显然存在决策包容性
排序后用个set维护一下就是\(O(n\log n)\)的
但是这个出题人怎么这么懒不写spj啊还要输出字典序最大方案。
考虑重排序列,在不改变答案最大的前提下,我们可以二分这个位置还能放哪些数(同样存在决策包容性,因而有单调性),然后因为n才5000,我们可以暴力贪心判断换成更大的数后是否合法,应该可以做到\(O(n^2\log n)\)不过比较懒的话用个set也能\(O(n^2\log^2 n)\)
扔给队友写了于是没有代码

标签:Contest,int,gym102082,nxt2,nxt1,2018,ans,col,dis
From: https://www.cnblogs.com/henry-1202/p/16631604.html

相关文章

  • 【Virt.Contest】CF1321(div.2)
    第一次打虚拟赛。CF传送门T1:ContestforRobots统计\(r[i]=1\)且\(b[i]=0\)的位数\(t1\)和\(r[i]=0\)且\(b[i]=1\)的位数\(t2\)。两个数都为\(0\)或都为......
  • 【Virt.Contest】CF1215(div.2)
    第二次打虚拟赛。CF传送门T1:YellowCards黄色卡片中规中矩的\(T1\)。首先可以算出一个人也不罚下时发出的最多黄牌数:\(sum=a1*(k1-1)+a2*(k2-1)\)此时,若\(sum>=n......
  • [XMAN2018排位赛]AutoKey
    1、得到USB流量,首先了解AutoKey是什么自动秘钥密码(Autokey)_不会学习的小菜鸡的博客-CSDN博客_autokey密码2、安装UsbKeyboardDataHacker.py工具GitHub-WangYihang/......
  • 洛谷P4619 [SDOI2018]旧试题
    再做一遍,算是复健一下数论。题目链接Description\(T\)组数据,给出\(A,B,C\),求\[\sum_{i=1}^A\sum_{j=1}^B\sum_{k=1}^Cd(ijk)\]\(d\)表示正因子个数。答案对\(P=1......
  • NC24263 USACO 2018 Feb G]Directory Traversal
    题目链接题目题目描述奶牛Bessie令人惊讶地精通计算机。她在牛棚的电脑里用一组文件夹储存了她所有珍贵的文件,比如:bessie/folder1/file1folder2/f......
  • 可信计算学习笔记 - 服务器可信支撑平台【GB/T 36639-2018】
    服务器可信支撑平台主要由物理可信根、可信基础组件和虚拟可信组件等部分组成根据服务器软硬件组成的不同,服务器可信支撑平台包含的部分也不同服务器硬件系统:应包......
  • P5021 [NOIP2018 提高组] 赛道修建 思路简记
    发现答案具有单调性,尝试一下二分答案能不能做二分答案\(t\)后,问题的关键就变成最多能找到多少条长度大于等于\(t\)的赛道我们先假设整棵树以\(1\)为根把样例的图......
  • [网鼎杯 2018]Comment-1|SQL注入|二次注入
    1、打开之后只有一个留言页面,很自然的就想到了二次注入得问题,顺带查看了下源代码信息,并没有什么提示,显示界面如下:2、那先扫描一下目录,同时随便留言一个测试以下,但是显示......
  • AtCoder Beginner Contest 263(Java)
    A题桶排序1importjava.util.*;2publicclassMain{3publicstaticvoidmain(String[]args){4Scannersc=newScanner(System.in);5......
  • 2018软测错题集
    1、     ......