zoukankan      html  css  js  c++  java
  • 2018-5-30 总结

    2018-5-21 ~ 2018-5-30集训感想

    首先 感谢 xiaoyao24256大佬 给我的blog(虽然只用一天QWQ)

    这几天来到了浙江集训 爽爆(假的qwq)

    尽管这几天学到了好多知识 但我还是个蒟蒻555

    从5.29的ACM赛先说吧

    比赛名称叫ACM欢乐赛,做题不欢乐,但是吃KFC吃的很欢乐嘿嘿嘿

    一开始的时候 我们小组比其他小组早A了前2道题(虽然不是最早)

    然后然后然后我就很开心

    于是我们就卡在了第三题……

    我们组一个大佬想出来了一个gcd的算法(我不会告诉你他就是给我号的人)

    结果不知道什么玄学原因 我们组否认了这个算法 去刚第四题

    为什么要否认呢?我也不知道啊……鬼知道那就是正解qwq

    附上核心代码

     1 read(p) , read(q) , read(b);
     2         
     3 register ll Gcd = gcd(p,q);
     4 q /= Gcd;
     5 Gcd = b;
     6         
     7 for(; q!=-1; ) {
     8     Gcd = gcd(q,Gcd);
     9     q /= Gcd;
    10     if(Gcd == 1)    break;
    11 }
    12         
    13 if(q == 1)    puts("Finite");
    14 else    puts("Infinite");

    第四题……不想说什么了

    我推了快1个小时的数学解

    然后推出来了一个玄学的东西:

    if len%4 == 1 输出头尾各一个数

    if len%4 == 2 输出头尾各2个数

    if len%4 == 3 输出第一个数、第三个数、倒一、倒三这些数

    if len%4 == 0 输出所有数

    正当我推得非常开心的时候 验证了下len=12的情况

    然后就发现这个做法是错误的

    于是 MMP ……

    比赛结束之后我才发现这道是一道非常!水的!区间DP

    哇哇哇气死了

    依然附上代码

    1 for(register int i=n-1; i>=1; i--) {
    2     for(register int j=i+1; j<=n; j++) {
    3         f[i][j] = f[i][j-1] ^ f[i+1][j];
    4         g[i][j] = maxest(f[i][j],g[i][j-1],g[i+1][j]);
    5     }
    6 }

    我们最后选择直接去看第7题(垃圾AtCoder)

    想出了两个类似正解的方法

    嗯其实不是正解 最后测了WA的不要不要的

    逃)

    嗯那两个算法就是打表和随机数

    事实证明打表能过更多的点

    诶呀打表是我想出来的~

    我觉得我可以把表交上来

    嗯算了太大了不交了qwq

    我不会告诉你我其实在凑字数

    好了好了我们来讲一下正事吧

    线段树

    对这就是一个很神奇的东西

    我们先来引入一个题目:戳我

    假如说这道题目没有修改这这个操作,我们用前缀和维护一下就行了

    加了修改之后,我们能想到的最朴素的做法是什么呢?
    当然就是枚举 L - R 之间每个数然后加上x

    求和也是一项一项加起来,这样复杂的是O(N^2)的

    一看数据,喊出GG~

    那我们有没有什么奇技淫巧降低复杂度呢?

    线段树就是为了这个而生的。

    就让我来简介一下线段树吧:

    线段树是一个二叉树,每个子节点里存放一段区间的左右边界还有子节点的信息,可以是一段区间的和、最大值、最小值等等等等

    为了更好的理解线段树,我厚颜无耻的拿了网上某个大佬的图来解释

    算了中间一堆可以介绍的现在也写不了了,就不介绍了,有没感觉自己期待了半天却……嗯哼~

    我直接贴代码了欸嘿

     1 // luogu-judger-enable-o2
     2 #include <iostream>
     3 #include <cstdio>
     4 
     5 using namespace std;
     6 
     7 typedef long long ll;
     8 const int Maxn = 400010;
     9 int n , m;
    10 int a[Maxn];
    11 struct SegmentTree {
    12     ll sum;    /* 1的总数 */
    13     ll tag;    /* 标记 */
    14     int leftbound;
    15     int rightbound;
    16 } Tree[Maxn];
    17 
    18 inline void Build(int root, int left , int right) {
    19     
    20     Tree[root].leftbound = left;
    21     Tree[root].rightbound = right;
    22     if(left == right)    Tree[root].sum = a[left];
    23     else {
    24         register int Mid = ( left + right ) / 2;
    25         Build(root*2,left,Mid);
    26         Build(root*2+1,Mid+1,right);
    27         Tree[root].sum = Tree[root*2].sum + Tree[root*2+1].sum;
    28     }
    29     
    30 }
    31 
    32 inline void Downtag(int root) {
    33     
    34     if(Tree[root].tag) {
    35         Tree[root*2].tag += Tree[root].tag;
    36         Tree[root*2+1].tag += Tree[root].tag;
    37         Tree[root*2].sum += ( Tree[root*2].rightbound - Tree[root*2].leftbound + 1 ) * Tree[root].tag;
    38         Tree[root*2+1].sum += ( Tree[root*2+1].rightbound - Tree[root*2+1].leftbound + 1 ) * Tree[root].tag;
    39         Tree[root].tag = 0;
    40     }
    41     
    42 }
    43 
    44 inline void Modify(int root , int left , int right , int delta) {
    45     
    46     if(Tree[root].leftbound >= left && Tree[root].rightbound <= right) {
    47         Tree[root].tag += delta;
    48         Tree[root].sum += ( Tree[root].rightbound - Tree[root].leftbound + 1 ) * delta;
    49     } else {
    50         Downtag(root);
    51         register int Mid = ( Tree[root].leftbound + Tree[root].rightbound ) / 2;
    52         if(left <= Mid)    Modify(root*2,left,right,delta);
    53         if(right > Mid)    Modify(root*2+1,left,right,delta);
    54         Tree[root].sum = Tree[root*2].sum + Tree[root*2+1].sum;
    55     }
    56     
    57 }
    58 
    59 inline ll Query(int root , int left , int right) {
    60     
    61     if(Tree[root].leftbound >= left && Tree[root].rightbound <= right) {
    62         return Tree[root].sum;
    63     } else {
    64         Downtag(root);
    65         register ll ans = 0;
    66         register int Mid = ( Tree[root].leftbound + Tree[root].rightbound ) / 2;
    67         if(left <= Mid)    ans += Query(root*2,left,right);
    68         if(right > Mid)    ans += Query(root*2+1,left,right);
    69         return ans;
    70     }
    71     
    72 }
    73 
    74 int main() {
    75     
    76     scanf("%d%d",&n,&m);
    77     
    78     for(register int i=1; i<=n; i++)
    79         scanf("%d",&a[i]);
    80     
    81     Build(1,1,n);
    82     
    83     for(register int i=1,x,y,z,k; i<=m; i++) {
    84         scanf("%d%d%d",&z,&x,&y);
    85         if(z == 1) {
    86             scanf("%d",&k);
    87             Modify(1,x,y,k);
    88         } else    printf("%lld
    ",Query(1,x,y));
    89     }
    90     
    91     return 0;
    92     
    93 }

    额开头那个氧气优化别在意哈~

    树状数组

    这个东西嘛

    跟线段树很像的

    就是用一个lowbit瞎**搞

    然后利用logn的时间求出来

    这里放一个题目:戳我

    代码如下qwq

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std ;
     4 
     5 const int MAXN = 500010;
     6 int n,m;
     7 int a[MAXN];
     8 int c[MAXN];
     9 
    10 inline void read(int &x) {
    11     int num = 0 , negative = 0;
    12     char ch = getchar();
    13     
    14     while((ch < '0' || ch > '9') && ch != '-')
    15         ch = getchar();
    16     
    17     if(ch == '-')    negative = 1;
    18     else    num = ch - '0';
    19     
    20     ch = getchar();
    21     
    22     while(ch >= '0' && ch <= '9') {
    23         num = num * 10 + ch - '0';
    24         ch = getchar();
    25     }
    26     
    27     x = num;
    28     if(negative)
    29         x = -x;
    30 }
    31 
    32 inline int lowbit(int x) {
    33     return x & (-x);
    34 }
    35 
    36 inline int sum(int x) {
    37     int ans = 0;
    38     for(int i=x; i>0; i-=lowbit(i))
    39         ans += c[i];
    40     return ans;
    41 }
    42 
    43 inline void add(int x , int y) {
    44     for(int i=x; i<=n; i+=lowbit(i))
    45         c[i] += y;
    46 }
    47 
    48 int main() {
    49     
    50     read(n) , read(m);
    51     for(int i=1; i<=n; i++) {
    52         read(a[i]);
    53         add(i,a[i]);
    54     }
    55     
    56     for(int i=1,z,x,y; i<=m; i++) {
    57         read(z) , read(x) , read(y);
    58         if(z == 1)    add(x,y);
    59         if(z == 2)    printf("%d
    ",sum(y) - sum(x-1));
    60     }
    61     
    62     return 0;
    63     
    64 }

    讲个笑话,树状数组的题都能用线段树短

    那为什么我们还要树状数组呢?

    当然是因为代码短、更好写了啦~

    LCA 最近公共祖先问题

    例题:戳我

    LCA 是什么意思呢 Largest China Apple?

    哦哦哦哦哦不对当然不是这样

    求出最近公共祖先有什么tarjan算法,还要什么病茶几and check

    本蒟蒻这里就不介绍了,这里介绍一个倍增的算法

    倍增呢,是一个神奇的东西,就是把2^p化成2^(p-1) + 2^(p-1)

    然后瞎**搞啦!

    附上代码

     1 // luogu-judger-enable-o2
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cmath>
     5 
     6 using namespace std;
     7 
     8 const int Maxn = 500010;
     9 int n , m , s , tot , maxdep;
    10 int last[Maxn];
    11 int depth[Maxn];    /* depth[i] : i的深度 */
    12 int f[Maxn][20];    /* f[i][k] : i的第2^k祖先 */
    13 
    14 struct Edge {
    15     int to;
    16     int next;
    17 } e[Maxn*2];
    18 
    19 inline void add(int u , int v) {
    20     tot ++;
    21     e[tot].to = v;
    22     e[tot].next = last[u];
    23     last[u] = tot;
    24 }
    25 
    26 inline void dfs(int x , int fa) {
    27     
    28     depth[x] = depth[fa] + 1;
    29     maxdep = max(maxdep,depth[x]);
    30     f[x][0] = fa;
    31     
    32     for(register int i=1; (1<<i)<=depth[x]; i++)
    33         f[x][i] = f[f[x][i-1]][i-1];
    34     /* x的第2^k祖先 = x的第2^(k-1)祖先的第2^(k-1)祖先 */
    35     
    36     for(register int i=last[x]; i; i=e[i].next) {
    37         register int y = e[i].to;
    38         if(y != fa)    dfs(y,x);    /* 遍历儿子 */
    39     }
    40     
    41 }
    42 
    43 inline int lca(int a , int b) {
    44     
    45     if(a == b)    return a;
    46     if(depth[a] > depth[b])    swap(a,b);
    47     
    48     for(register int i=maxdep; i>=0; i--)
    49         if(depth[a] <= depth[b] - (1<<i))
    50             b = f[b][i];
    51     /* 一个数一定会由2^k+2^m+2^p+...组成
    52        a的深度和b的深度的差距也一定会由2^k+2^m+2^p+...组成
    53        所以最终一定会到同一层 */
    54     
    55     if(a == b)    return a;
    56     
    57     for(register int i=maxdep; i>=0; i--) {
    58         if(f[a][i] == f[b][i])    continue;    /* continue的作用是找a和b的最近祖先 */
    59         else    a = f[a][i] , b = f[b][i];
    60     }
    61     
    62     return f[a][0];
    63     
    64 }
    65 
    66 int main() {
    67     
    68     scanf("%d%d%d",&n,&m,&s);
    69     for(register int i=1,x,y; i<n; i++) {
    70         scanf("%d%d",&x,&y);
    71         add(x,y);
    72         add(y,x);
    73     }
    74     
    75     dfs(s,0);
    76     
    77     maxdep = log2(maxdep);
    78     for(register int u,v; m--; ) {
    79         scanf("%d%d",&u,&v);
    80         printf("%d
    ",lca(u,v));
    81     }
    82     
    83     return 0;
    84     
    85 }

    这里插一句,集训的时候我们去了上海交♂大和上海纽扣大学啊呸

    然后身份证丢了……为什么呢?无可奉告。

    最后还是感谢海亮的老师们,帮我各种联系找到了身份证

    就不用用半条命换钱包了

    数论~

    数论当然不是一个算法啦

    当时就是万恶的数论害的我……哇呜呜呜呜不说了

    这里说个exgcd,扩展欧几里得算法

    证明可以说是能用几个词来形容了

    就是 naive 显而易见 易证 轻松的得到了啦

    啊呸啊呸我都说了什么

    好了 我搞个板子下来 凑个字数啦~

     1 template < typename Typ >
     2 inline Typ exgcd(Typ a , Typ b , Typ &x , Typ &y) {
     3     
     4     if(!b) {
     5         x = (Typ)1;
     6         y = (Typ)0;
     7         return a;
     8     }
     9     
    10     register Typ Gcd = exgcd(b,a%b,x,y);
    11     
    12     register Typ tmp = x;
    13     x = y;
    14     y = tmp - a / b * y;
    15     
    16     return Gcd;
    17     
    18 }

    template那一行是什么意思呢?

    一站式满足:戳我

    没想到吧 ->此处省略邪笑

    manacher和kmp算法

    简称马拉车和看*片 

    马拉车例题:戳我,看*片例题:戳我

    你什么都没听到qwq

    这两个算法是我见过的很玄学的算法

    已经懒了,所以有代码qwq

    先是马拉车

     1 // luogu-judger-enable-o2
     2 #include <iostream>
     3 #include <cstring> 
     4 #include <cstdio>
     5 
     6 const int Maxn = 11000010;
     7 char s[Maxn];
     8 int pal[2*Maxn];
     9 
    10 inline void read() {
    11     
    12     register int len = -1;
    13     register char ch = getchar();
    14     
    15     while(ch != EOF) {
    16         s[++len] = ch;
    17         ch = getchar();
    18     }
    19     
    20 }
    21 
    22 int main() {
    23     
    24     read();
    25     
    26     register int len = strlen(s);
    27     
    28     register int l = -1 , r = -1 , ans = 0;
    29     
    30     for(register int z=0; z<2*len; z++) {
    31         register int i = ( z + 1 ) >> 1;
    32         register int j = z >> 1;
    33         register int p = 0;
    34         if(i < r)    p = std :: min(r-i,pal[2*(l+r)-z]);
    35         while(j+p+1 < len && i-p-1 >= 0 && s[j+p+1] == s[i-p-1])    p ++;
    36         if (j + p > r) {
    37             r = j + p;
    38             l = i - p;
    39         }
    40         pal[z] = p;
    41         register int tmp = 2 * p + 1;
    42         if( z & 1 )    tmp --;
    43         ans = std :: max(ans,tmp);
    44     }
    45     
    46     printf("%d
    ",ans);
    47     
    48     return 0;
    49     
    50 }

    然后看*片

     1 // luogu-judger-enable-o2
     2 #include <iostream>
     3 #include <cstdio>
     4 
     5 using namespace std;
     6 
     7 const int Maxn = 1000010;
     8 int len1 , len2;
     9 string x , y , a , b;
    10 int next[Maxn];
    11 
    12 int main() {
    13     
    14     cin >> a >> b;
    15     
    16     len1 = a.size();
    17     len2 = b.size();
    18     
    19     x.resize(len1);
    20     y.resize(len2);
    21     
    22     for(register int i=1; i<=len1; i++)    x[i] = a[i-1];
    23     for(register int i=1; i<=len2; i++)    y[i] = b[i-1];
    24     
    25     next[1] = 0;
    26     
    27     for(register int i=2,j=0; i<=len2; i++) {
    28         while(j && y[i] != y[j+1])    j = next[j];
    29         if(y[i] == y[j+1])    j ++;
    30         next[i] = j;
    31     }
    32     
    33     for(register int i=1,j=0; i<=len1; i++) {
    34         while(j && x[i] != y[j+1])    j = next[j];
    35         if(x[i] == y[j+1])    j ++;
    36         if(j == len2) {
    37             printf("%d
    ",i-len2+1);
    38             j = next[j];
    39         }
    40     }
    41     
    42     for(register int i=1; i<=len2; i++)
    43         printf("%d ",next[i]);
    44     putchar('
    ');
    45     
    46     return 0;
    47     
    48 }

    wow~我凑了好多字啦

    啊呸啊呸没什么

    下面讲一个非常容易理解的字符串算法

    猜猜看是什么?

    Trie树

    简单介绍下,就是把字符串每个字符弄成个子节点,然后暴力遍历一遍就行了

    模板题:戳我

    没想到吧!题目名称这么怪

    我又要想个借口贴模板啦!嗯就是这题比较简单

    于是上~模~板~

     1 // luogu-judger-enable-o2
     2 #include <iostream>
     3 #include <cstring>
     4 #include <cstdio>
     5 
     6 using namespace std;
     7 
     8 const int Maxn = 10010;
     9 const int Son = 30;
    10 int n , m , num;
    11 struct Trie {
    12     bool flag;
    13     bool first;
    14     int son[Son];
    15 } t[Maxn*50];
    16 
    17 inline void insert(string s) {
    18     
    19     register int u = 0;
    20     register int len = s.size();
    21     
    22     for(register int i=0; i<len; i++) {
    23         register int v = int ( s[i] - 'a' + 1 );
    24         if(!t[u].son[v])    t[u].son[v] = ++ num;
    25         u = t[u].son[v];
    26     }
    27     
    28     t[u].flag = true;
    29     
    30 }
    31 
    32 inline int query(string s) {
    33     
    34     register int u = 0;
    35     register int len = s.size();
    36     register int state = 0;
    37     
    38     for(register int i=0; i<len; i++) {
    39         register int v = int ( s[i] - 'a' + 1 );
    40         if(!t[u].son[v])    return 1;
    41         u = t[u].son[v];
    42     }
    43     
    44     if(!t[u].flag)    return 1;
    45     if(t[u].first)    return 2;
    46     t[u].first = true;
    47     return 0;
    48     
    49 }
    50 
    51 int main() {
    52     
    53     register string name;
    54     
    55     scanf("%d",&n);
    56     for(register int i=1; i<=n; i++) {
    57         cin >> name;
    58         insert(name);
    59     }
    60     scanf("%d",&m);
    61     for(; m--; ) {
    62         cin >> name;
    63         register int state = query(name);
    64         if(!state)    puts("OK");
    65         else if(state == 1)    puts("WRONG");
    66         else    puts("REPEAT");
    67     }
    68     
    69     return 0;
    70     
    71 }

     全新算法:AC自动机

    这个算法很神奇,只要交上去就会自动A题,分分钟成为Rank1,妈妈再也不用担心我的OI生活啦

    等下。。。看错算法了,那个算法是自动AC机QWQ

    这个算法呢,就是要你熟练的掌握看*片算法和Trie树

    然后结合起来跑一遍就行了

    有2道模板题:

    简单版:戳我  提高版:戳我

    不用说的啦~先附上代码~

    简单版:

     1 // luogu-judger-enable-o2
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <queue>
     5 
     6 using namespace std;
     7 
     8 const int Maxn = 1000010;
     9 const int Maxm = 30;
    10 int n , cnt;
    11 
    12 struct Trie {
    13     int fail;
    14     int end;
    15     int num[Maxm];
    16 } t[Maxn];
    17 
    18 inline void Build(string s) {
    19     
    20     register int len = s.size();
    21     register int now = 0;
    22     
    23     for(register int i=0; i<len; i++) {
    24         register int to = s[i] - 'a' + 1;
    25         if(!t[now].num[to])    t[now].num[to] = ++ cnt;
    26         now = t[now].num[to];
    27     }
    28     
    29     t[now].end ++;
    30     
    31 }
    32 
    33 inline void Getfail() {
    34     
    35     queue <int> Q;
    36     
    37     for(register int i=1; i<=26; i++) {
    38         if(t[0].num[i]) {
    39             t[t[0].num[i]].fail = 0;
    40             Q.push(t[0].num[i]);
    41         }
    42     }
    43     
    44     while(!Q.empty()) {
    45         register int now = Q.front();
    46         Q.pop();
    47         for(register int i=1; i<=26; i++) {
    48             if(t[now].num[i]) {
    49                 t[t[now].num[i]].fail = t[t[now].fail].num[i];
    50                 Q.push(t[now].num[i]);
    51             } else    t[now].num[i] = t[t[now].fail].num[i];
    52         }
    53     }
    54     
    55 }
    56 
    57 inline int Query(string s) {
    58     
    59     register int len = s.size();
    60     register int now = 0 , ans = 0;
    61     
    62     for(register int i=0; i<len; i++) {
    63         register int to = s[i] - 'a' + 1;
    64         now = t[now].num[to];
    65         for(register int j=now; j&&t[j].end; j=t[j].fail) {
    66             ans += t[j].end;
    67             t[j].end = 0;
    68         }
    69     }
    70     
    71     return ans;
    72     
    73 }
    74 
    75 int main() {
    76     
    77     register string s;
    78     
    79     scanf("%d",&n);
    80     for(register int i=1; i<=n; i++) {
    81         cin >> s;
    82         Build(s);
    83     }
    84     
    85     t[0].fail = 0;
    86     
    87     Getfail();
    88     
    89     cin >> s;
    90     
    91     cout << Query(s) << endl;
    92     
    93     return 0;
    94     
    95 }

    吐槽一句luogu数据貌似有点水嗯哼

    现在来提高版:

      1 #include <algorithm>
      2 #include <iostream>
      3 #include <cstring>
      4 #include <cstdio>
      5 #include <queue>
      6 
      7 using namespace std;
      8 
      9 const int Maxn = 100010;
     10 const int Maxm = 30;
     11 int n , cnt;
     12 string s[Maxn];
     13 queue <int> Q;
     14 
     15 struct Trie {
     16     int fail;
     17     int end;
     18     int num[Maxm];
     19 } t[Maxn];
     20 
     21 struct Str {
     22     int id;
     23     int tot;
     24 } a[Maxn];
     25 
     26 inline void Clean(int x) {
     27     
     28     t[x].end = t[x].fail = 0;
     29     for(register int i=1; i<=26; i++)
     30         t[x].num[i] = 0;
     31     
     32 }
     33 
     34 inline bool comp(const Str &x , const Str &y) {
     35     if(x.tot > y.tot)    return true;
     36     if(x.tot < y.tot)    return false;
     37     return x.id < y.id;
     38 }
     39 
     40 inline void Build(string s , int idx) {
     41     
     42     register int len = s.size();
     43     register int now = 0;
     44     
     45     for(register int i=0; i<len; i++) {
     46         register int to = s[i] - 'a' + 1;
     47         if(!t[now].num[to]) {
     48             t[now].num[to] = ++ cnt;
     49             Clean(cnt);
     50         }
     51         now = t[now].num[to];
     52     }
     53     
     54     t[now].end = idx;
     55     
     56 }
     57 
     58 inline void Getfail() {
     59     
     60     while(!Q.empty())    Q.pop();
     61     
     62     for(register int i=1; i<=26; i++) {
     63         if(t[0].num[i]) {
     64             t[t[0].num[i]].fail = 0;
     65             Q.push(t[0].num[i]);
     66         }
     67     }
     68     
     69     while(!Q.empty()) {
     70         register int now = Q.front();
     71         Q.pop();
     72         for(register int i=1; i<=26; i++) {
     73             if(t[now].num[i]) {
     74                 t[t[now].num[i]].fail = t[t[now].fail].num[i];
     75                 Q.push(t[now].num[i]);
     76             } else    t[now].num[i] = t[t[now].fail].num[i];
     77         }
     78     }
     79     
     80 }
     81 
     82 inline void Query(string s) {
     83     
     84     register int len = s.size();
     85     register int now = 0;
     86     
     87     for(register int i=0; i<len; i++) {
     88         register int to = s[i] - 'a' + 1;
     89         now = t[now].num[to];
     90         for(register int j=now; j; j=t[j].fail)
     91             a[t[j].end].tot ++;
     92     }
     93     
     94 }
     95 
     96 int main() {
     97     
     98     while(scanf("%d",&n) != EOF) {
     99         
    100         if(!n)    return 0;
    101         
    102         cnt = 0;
    103         Clean(0);
    104         
    105         for(register int i=1; i<=n; i++) {
    106             cin >> s[i];
    107             a[i].id = i;
    108             a[i].tot = 0;
    109             Build(s[i],i);
    110         }
    111         
    112         Getfail();
    113         
    114         cin >> s[0];
    115         Query(s[0]);
    116         
    117         sort(a+1,a+n+1,comp);
    118         
    119         printf("%d
    ",a[1].tot);
    120         cout << s[a[1].id] << endl;
    121         for(register int i=2; i<=n; i++) {
    122             if(a[i].tot != a[i-1].tot)    break;
    123             cout << s[a[i].id] << endl;
    124         }
    125         
    126     }
    127     
    128     return 0;
    129     
    130 }

    其实提高版不难,加个排序等奇奇gaygay的操作就行了QVQ

    哦对了,这些字符串算法全是一个dalao讲的

    在这里我要疯狂%%%%%%%飞神

    我能记起来的最后一个算法:

    差分约束

    其实这个就是个转成SPFA的算法

    利用三角形不等式,dis[i] + e[i].w < dis[j] 然后……

    还有各种判环就行了啦~so~easy~

    模板题:戳我

    附上代码~

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <queue>
      4 
      5 using namespace std;
      6 
      7 typedef long long ll;
      8 const int Maxn = 100010;
      9 int n , m , tot;
     10 int repeat[Maxn];
     11 int last[Maxn];
     12 int dis[Maxn];
     13 bool vis[Maxn];
     14 
     15 struct Edge {
     16     int to;
     17     int w;
     18     int next;
     19 } e[(Maxn<<1)+Maxn];
     20 
     21 queue < int > Q;
     22 
     23 template < typename Typ >
     24 inline void read(Typ &x) {
     25     
     26     register Typ num = 0;
     27     register char ch = getchar();
     28     
     29     while(ch < '0' || ch > '9')    ch = getchar();
     30     
     31     while(ch >= '0' && ch <= '9') {
     32         num = ( num << 3 ) + ( num << 1 ) + ch - '0';
     33         ch = getchar();
     34     }
     35     
     36     x = num;
     37     
     38 }
     39 
     40 inline void add(int u , int v , int w) {
     41     tot ++;
     42     e[tot].to = v;
     43     e[tot].w = w;
     44     e[tot].next = last[u];
     45     last[u] = tot;
     46 }
     47 
     48 inline bool Spfa(int s) {
     49     
     50     while(!Q.empty())    Q.pop();
     51     vis[s] = true;
     52     Q.push(s);
     53     
     54     while(!Q.empty()) {
     55         register int u = Q.front();
     56         Q.pop();
     57         vis[u] = false;
     58         for(register int i=last[u]; i; i=e[i].next) {
     59             register int v = e[i].to;
     60             if(dis[u] + e[i].w > dis[v]) {
     61                 repeat[v] ++;
     62                 if(repeat[v] >= n)    return false;
     63                 dis[v] = dis[u] + e[i].w;
     64                 if(!vis[v]) {
     65                     vis[v] = true;
     66                     Q.push(v);
     67                 }
     68             }
     69         }
     70     }
     71     
     72     return true;
     73     
     74 }
     75 
     76 inline ll getsum() {
     77     
     78     register ll sum = 0;
     79     
     80     for(register int i=1; i<=n; i++)
     81         sum += dis[i];
     82         
     83     return sum;
     84     
     85 }
     86 
     87 int main() {
     88     
     89     read(n) , read(m);
     90     for(register int x,y,z; m--; ) {
     91         read(z) , read(x) , read(y);
     92         if(z == 1)    add(x,y,0) , add(y,x,0);
     93         if(z == 2) {
     94             if(x == y)    return !puts("-1");
     95             add(x,y,1);
     96         }
     97         if(z == 3)    add(y,x,0);
     98         if(z == 4) {
     99             if(x == y)    return !puts("-1");
    100             add(y,x,1);
    101         }
    102         if(z == 5)    add(x,y,0);
    103     }
    104     
    105     for(register int i=n; i>=1; i--)
    106         add(0,i,1);
    107     
    108     register bool tmp = Spfa(0);
    109     if(!tmp)    puts("-1");
    110     else    printf("%lld
    ",getsum());
    111     
    112     return 0;
    113     
    114 }

    好了~

    我觉得总结好了呢~

    可是并没有呢~

    等到集训结束后我们再见面吧~

    By  BlueCat

  • 相关阅读:
    echo
    shell
    grub
    find
    脚本案例
    dd if= of= MBR
    cat <<EOF> file
    fieldset——一个不常用的HTML标签
    闪烁图片
    跑马灯效果
  • 原文地址:https://www.cnblogs.com/xiaoyao24256/p/9111843.html
Copyright © 2011-2022 走看看