10-8 DAIRY

来源:互联网 发布:截面数据常用模型 编辑:程序博客网 时间:2024/06/14 09:03

前几天没写完的都是要么难以理解要么懒得打题了【工业】
今天也来划水~~~

今天的出题人何爷爷因为太帅(lan)气(duo)了,所以solution…不存在的(tan90°)
【hyy:我什么时候写过solution?】

T1 Graph 0
审题要仔细,做题更要仔细。不要在做题的时候就忘记了题目有两个小问!
很惨的爆0了一道真的就没有什么思考难度的题。

第一问:求最多的次数。
很明显就是每个连通块内边数>>1累加起来。

第二问:所以我就是写代码写着写着不记得要输出方案了。(毕竟是最后才开始写这道题)
也很明显,我们dfs时顺便就把方案记录一下。【完全ojbk…】
满分修改如下:

#include<cstdio>#include<cstdlib>#include<iostream>#include<algorithm>#include<cstring>#include<vector>using namespace std;const int N = 100010;const int M = 200010;vector<int> V[N];int n, m, ans, e, cnt;int pre[N], fa[N];int to[M<<1], nxt[M<<1], head[N];template <typename T>T read(){    T N(0), F(1);    char C = getchar();    for(; !isdigit(C); C = getchar()) if(C == '-') F = -1;    for(; isdigit(C); C = getchar()) N = N*10 + C-48;    return N*F;}void add(int u, int v){    to[++e] = v; nxt[e] = head[u]; head[u] = e;    to[++e] = u; nxt[e] = head[v]; head[v] = e;}int find(int x){ return x == fa[x] ? x : fa[x] = find(fa[x]); }void dfs(int u, int f = 0){    pre[u] = ++cnt;    for(int i = head[u]; i; i = nxt[i]){        int v = to[i];        if(v == f) continue;        if(!pre[v]){            fa[v] = u;            dfs(v, u);        }        else if(pre[v] < pre[u]){            V[u].push_back(v);        }    }    if(fa[u]){        if(V[u].size() & 1) V[u].push_back(fa[u]);        else V[fa[u]].push_back(u);    }}int main(){    freopen("graph.in", "r", stdin);    freopen("graph.out","w",stdout);    n = read<int>(); m = read<int>();    for(int i = 1; i <= m; i++){        int u = read<int>();        int v = read<int>();        add(u, v);    }    for(int i = 1; i <= n; i++){        if(!pre[i]) dfs(i);    }    for(int i = 1; i <= n; i++){        ans += V[i].size() >> 1;    }    printf("%d\n", ans);    for(int i = 1; i <= n; i++){        for(int j = 1; j < V[i].size(); j += 2){            printf("%d %d %d\n", V[i][j-1], i, V[i][j]);        }    }    return 0;}

T2 permutation 50
我也不知道一个完全没有正确性的做法怎么有50分的,但是据说连什么爆搜都搜出了90(笑)
我的考场想法是:
序列从前往后的确定每一个位置的最终数字。其实肯定不是最终的,(非正确做法)但我觉得能水过去一些点吧。这里我是怎么确定的呢,我不是往后>=k位一个个判断的,这样明显浪费时间。因为观察到是一个排列,所以数字和所在位置一定都是1~n的,这样我又开一个数组b[i]记录i这个数字当前所在位置。题目要求数值差==1。故每次只要判断比当前位数值小1的数值在哪个位置,这个位置是否与当前位相差>=k,符合就交换,不符合就视作已达到最终结果。

有一股贪心的味儿(#`O′)
正解我还没怎么弄明白,还是有些难度的。(记不太清hyy的讲解了)这个题思路需要转化一下。题目要求数值差为1,位置差>=k,可以转化为另一序列要求位置差为1,数值差

#include<cstdio>#include<cstdlib>#include<iostream>#include<algorithm>#include<cstring>using namespace std;const int oo = 1000007;const int N = 500010;int n, k, x, y, tmp;int a[N], p[N];template <typename T>T read(){    T N(0), F(1);    char C = getchar();    for(; !isdigit(C); C = getchar()) if(C == '-') F = -1;    for(; isdigit(C); C = getchar()) N = N*10 + C-48;    return N*F;}int main(){    freopen("permutation.in", "r", stdin);    freopen("permutation.out","w", stdout);    n = read<int>(); k = read<int>();    for(int i = 1; i <= n; i++){        a[i] = read<int>();        p[a[i]] = i;    }    a[0] = oo;    for(int i = 1; i <= n; i++){        while(a[p[a[i]-1]] < a[p[a[i]]] && p[a[i]-1] - p[a[i]] >= k){            x = a[i]-1, y = a[i];            a[p[x]] = y; a[p[y]] = x;            tmp = p[x]; p[x] = p[y]; p[y] = tmp;        }    }    for(int i = 1; i <= n; i++) printf("%d\n", a[i]);    return 0;}

T3 tree 100
国家集训队论问题被众人猜出结论直接秒题,让出题人hyy哭晕在厕所。
这是一道集训队论问题,然而…并不是我能去集训队了,而是this结论题实在太走运了。我写了个5pts暴力打了几组数据发现answer全部是权值和。就大胆猜测,省去证明(不会),直接当作结论题写了两行代码。

莫名其妙A掉了/???

#include<cstdio>#include<cstdlib>#include<iostream>#include<algorithm>#include<cstring>using namespace std;typedef long long ll;const int N = 100010;int n;ll ans;template <typename T>T read(){    T N(0), F(1);    char C = getchar();    for(; !isdigit(C); C = getchar()) if(C == '-') F = -1;    for(; isdigit(C); C = getchar()) N = N*10 + C-48;    return N*F;}int main(){    freopen("tree.in", "r", stdin);    freopen("tree.out","w",stdout);    n = read<int>();    for(int i = 1; i < n; i++){        int u = read<int>(); int v = read<int>(); ll w = read<ll>();        ans += w;    }    printf("%lld\n", ans);    return 0;}

考场写的5pts暴力如下,好像还有点问题,不过用来发现结论绰绰有余了(中间结果什么的没有注释掉,反正是用来找结论的):

#include<cstdio>#include<cstdlib>#include<iostream>#include<algorithm>#include<cstring>using namespace std;typedef long long ll;const ll oo = 1e18+7;const int N = 110;ll sum, ans, pn, h;int n, f;int vis[N], p[N], res[N];ll e[N][N], pth[N];template <typename T>T read(){    T N(0), F(1);    char C = getchar();    for(; !isdigit(C); C = getchar()) if(C == '-') F = -1;    for(; isdigit(C); C = getchar()) N = N*10 + C-48;    return N*F;}void dfs(int s, int t){    if(f) return;    if(s == t){        f = 1;//      for(int i = 1; i <= pn; i++){ sum = min(sum, pth[i]); printf("%lld ", pth[i]);}//      printf("\n");        return;    }    for(int i = 1; i <= n; i++){        if(e[s][i] != -1 && !vis[i]){            vis[i] = 1;            pth[++pn] = e[s][i];            dfs(i, t);            vis[i] = 0;            pn--;        }    }}int main(){    freopen("tree.in", "r", stdin);    freopen("tree.out","w",stdout);    n = read<int>();    for(int i = 1; i <= n; i++) p[i] = i;    for(int i = 1; i <= n; i++){        for(int j = 1; j <= n; j++){            e[i][j] = -1;        }    }    for(int i = 1; i < n; i++){        int u = read<int>();        int v = read<int>();        ll w = read<ll>();        e[u][v] = e[v][u] = w;    }    do{        h = 0LL;        for(int i = 1; i < n; i++){            int u = p[i];            int v = p[i+1];            memset(vis, 0, sizeof(vis));            vis[u] = 1; f = pn = 0; sum = oo;            dfs(u, v);            h += sum;        }    //  printf("%lld\n", h);//      ans = max(ans, h);        if(ans < h){            for(int i = 1; i <= n; i++) res[i] = p[i];            ans = h;        }    }while(next_permutation(p+1, p+n+1));    for(int i = 1; i <= n; i++) printf("%d ", res[i]);    printf("\n");    printf("%lld\n", ans);    return 0;}

证明其实也不难,不好写出来,感性理解一下。
首先显然ans的上界就是权值和,现在要证明ans的下界同样是权值和。
/*
一条边接A、B两点,必定不会从A->B->别的点->B->A->…
在经过A-B这条边前一定会把A那边一堆点包括什么循环回到A的点都走一遍,所以最佳方案不存在又绕回A这样的方案。
*/
我们把边权从小到大考虑,每次考虑一条边的时候,都把这棵树分成左右两棵树(两个子问题),而当前考虑的这条边必定会被经过,所以对答案的贡献必定会被算一次。划分成子问题考虑都是如此,所以每一条边都对答案至少产生一次贡献,所以ans必定是权值和。

原创粉丝点击