• Codeforces *1400-1600 做题记录


    看了题解的题目会标注*,题目按照 CF 默认顺序排序

    C. Skier

    题目链接

    题面说的是“路径”,而不是“点”。

    可以设最初滑雪者的位置在 (1,1),用 (map) (vis[id(i,j)][id(k,h)])(坐标展开成一维)记录 ((i,j)) ((k,h)) 两点之间是否访问过。

     #include <iostream>
     #include <cstring>
     #include <map>
     using namespace std;
     
     long long T, n, tot, x, y, ans;
     string s;
     map <long long, map <long long, long long> > vis;
     map <long long, map <long long, long long> > id;
     
     int main()
     {
         scanf("%lld", &T);
         while(T--)
         {
             cin >> s; n = s.size();
             x = 1, y = 1, ans = 0, tot = 0;
             id[1][1] = ++tot;
             for(int i = 0; i < n; i++)
             {
                 int now = id[x][y];
                 if(s[i] == 'N') x--;
                 if(s[i] == 'S') x++;
                 if(s[i] == 'W') y--;
                 if(s[i] == 'E') y++;
                 if(!id[x][y]) id[x][y] = ++tot;
                 if(vis[now][id[x][y]] || vis[id[x][y]][now])
                     ans += 1;
                 else ans += 5;
                 vis[now][id[x][y]] = vis[id[x][y]][now] = 1;
             }
             x = y = 1;
             for(int i = 0; i < n; i++)
             {
                 int now = id[x][y];
                 if(s[i] == 'N') x--;
                 if(s[i] == 'S') x++;
                 if(s[i] == 'W') y--;
                 if(s[i] == 'E') y++;
                 vis[now][id[x][y]] = vis[id[x][y]][now] = 0;
             }
             id[1][1] = 0, x = y = 1;
             for(int i = 0; i < n; i++)
             {
                 if(s[i] == 'N') x--;
                 if(s[i] == 'S') x++;
                 if(s[i] == 'W') y--;
                 if(s[i] == 'E') y++;
                 id[x][y] = 0;
             }
             vis[1][1] = 0;
             printf("%lld
    ", ans);
         }
         return 0;
     }
    

    C. Phoenix and Distribution

    题目链接

    首先考虑第一个字母:从小到大选择,如果第一个字母不同,答案就是其中最大的一个;

    剩下两种情况:所有的都摞在一起或平均分配,判断这两种情况谁的字典序小

     #include <iostream>
     #include <cstdio>
     #include <cstring>
     #include <algorithm>
     using namespace std;
     
     const int N = 233333;
     int T, n, k, tot, cnt1 = 0, cnt2 = 0;
     int a[N], c[N], d[N];
     string s;
     
     bool same(int x, int y)
     {
         for(int i = x + 1; i <= y; i++)
             if(a[i] != a[i - 1]) return false;
         return true;
     }
     
     bool cmp(int num1, int num2)
     {
         for(int i = 1; i <= min(num1, num2); i++)
         {
             if(c[i] != d[i] && c[i] < d[i]) return true;
             if(c[i] != d[i] && c[i] > d[i]) return false; 
         }
         if(num1 < num2) return true;
         return false;
     }
     
     int main()
     {
         scanf("%d", &T);
         while(T--)
         {
             scanf("%d%d", &n, &k);
             cin >> s;
             for(int i = 0; i < n; i++) a[i + 1] = s[i];
             sort(a + 1, a + n + 1); 
             if(!same(1, k)) 
             {
                 cout << (char)(a[k]) << "
    ";
                 continue;
             }
             tot = 1, cnt1 = cnt2 = 0;
             while(tot <= n)
             {
                 c[++cnt1] = a[min(n, tot + k - 1)];
                 if(!same(tot, min(n, tot + k - 1))) break;
                 tot += k;
             }
             d[++cnt2] = a[1];
             for(int i = k + 1; i <= n; i++) d[++cnt2] = a[i];
             if(cmp(cnt1, cnt2))
             {
                 for(int i = 1; i <= cnt1; i++)
                     cout << (char)(c[i]);
                 printf("
    ");
             }
             else
             {
                 for(int i = 1; i <= cnt2; i++)
                     cout << (char)(d[i]);
                 printf("
    ");
             }
         }
         return 0;
     }
    

    B. Phoenix and Beauty

    题目链接

    如果看做一个长度为 (k) 的窗口从左向右滑动,出去的必须等于进来的。所以,若数组中有超过 (k) 个元素,则输出 (-1)

    否则,构造前 (k) 个里面包含所有元素,不断向右滑动,遇到相等的就领走初始数组中的元素,直至初始数组为空

     #include <iostream>
     #include <cstdio>
     #include <cstring>
     #include <algorithm>
     using namespace std;
     
     const int N = 23333;
     int T, n, k, m, tot, a[N], use[N], b[N], c[N], d[N];
     
     int main()
     {
         cin >> T;
         memset(use, 0, sizeof(use));
         while(T--)
         {
             scanf("%d%d", &n, &k);
             int fl = 1, cnt = 0, tmp = 0;
             for(int i = 1; i <= n; i++)
                 scanf("%d", &a[i]), c[i] = a[i];
             sort(c + 1, c + n + 1);
             for(int i = 1; i <= n; i++)
                 if(c[i] != c[i - 1] || i == 1) d[++tmp] = c[i];
             for(int i = 1; i <= n; i++)
             {
                 if(!use[a[i]]) cnt++;
                 use[a[i]] = 1;
             }
             if(cnt <= k)
             {
                 tot = 1, m = k;
                 if(tmp >= k)
                     for(int i = 1; i <= k; i++) b[i] = d[i];
                 else
                 {
                     for(int i = 1; i <= k; i++) b[i] = 1;
                     for(int i = 1; i <= tmp; i++) b[i] = d[i];
                 }
                 while(tot <= n)
                 {
                     b[++m] = b[m - k];
                     if(b[m] == a[tot]) tot++;
                 }
                 printf("%d
    ", m);
                 for(int i = 1; i <= m; i++) printf("%d ", b[i]);
                 printf("
    ");
             }
             else printf("-1
    ");
             for(int i = 1; i <= n; i++) use[a[i]] = 0;
         } 
         return 0;
     }
    

    A. Hilbert's Hotel

    题目链接

    房间数是无限的,无法枚举,考虑枚举 (a[1-n])。先不考虑取模,最初能 (+a[i]) 的就是 (i) 号房,顺序推下去,能 (+a[i]) 的还有类似 (i+n)(i+2n)...这些房间 (mod) (n) 都等于 (i),加 (a[i]) 之后再取膜也是相等的

    (i) 号房和 (j) 号房转移到了同一个房间,说明 (i+xn+a[i]=j+a[j])(x) 是常数),此时 ((a[i]+i))%(n=(j+a[j]))%(n)。因此对于 (1≤i≤n),只需要标记((i+a[i])%n) 是否使用过

     #include <iostream>
     #include <map> 
     #include <cstdio>
     using namespace std;
     
     const int N = 2333333;
     long long T, n, a[N], vis[N];
     bool tmp;
     
     int main()
     {
         scanf("%lld", &T);
         while(T--)
         {
             scanf("%lld", &n);
             tmp = true;
             for(int i = 0; i < n; i++) scanf("%lld", &a[i]);
             for(int j = 0; j < n; j++)
             {
                 vis[(((j + a[j]) % n) + n) % n]++;
                 if(vis[(((j + a[j]) % n) + n) % n] > 1)
                     tmp = false;
             }
             for(int j = 0; j < n; j++)
                 vis[(((j + a[j]) % n) + n) % n] = 0;
             if(tmp == true) printf("YES
    ");
             else printf("NO
    ");
         }
         return 0;
     }
    

    C. Yet Another Counting Problem *

    题目链接

    保证 (a<b),打表找规律得从 (lcm(a,b)*x)(x≥0)(x) 是常数)开始 (b) 个数 %(a)%(b=)%(b)%(a)

    注意特判 (x=0),判断边界

     #include <iostream>
     #include <cstdio>
     #include <cstring>
     using namespace std;
     
     long long T, a, b, q, l, r, lcm;
     long long get(long long x)
     {
         long long res = (x / lcm + 1) * b;
         if(x % lcm < b) res -= b - 1, res += x % lcm;
         if(x >= b) res - 1;
         return max(0ll, res);
     }
     
     int main()
     {
         scanf("%lld", &T);
         while(T--)
         {
             scanf("%lld%lld%lld", &a, &b, &q);
             if(a > b) swap(a, b);
             for(int i = a * b; i > 0; i--)
                 if(i % a == 0 && i % b == 0)
                     lcm = i;
             for(int i = 1; i <= q; i++)
             {
                 scanf("%lld%lld", &l, &r);
                 printf("%lld ", r - l + 1 - get(r) + get(l - 1));
             }
             printf("
    ");
         }
         return 0;
     }
    

    A. Nastya and Strange Generator

    题目链接

    好像是写麻烦了...

    注意到 (r) 数组不是变成 (0),就是有增无减。所以在改变位置 (i) 时,使用并查集维护,把 (r_i)(r_{i+1}) 合并。然后再用线段树维护 (count) 的最值

     #include <iostream>
     #include <cstdio>
     #include <cstring>
     #include <algorithm>
     #define mid ((l + r) / 2)
     using namespace std;
      
     const int N = 233333;
     int T, n, x, max_, fl, a[N], cnt[N], fa[N], t[6666666];
      
     int find(int x)
     {
         return x == fa[x] ? x : fa[x] = find(fa[x]);
     }
      
     void build(int x, int l, int r)
     {
         if(l == r)
         {
             t[x] = 1;
             return ;
         }
         build(x * 2, l, mid);
         build(x * 2 + 1, mid + 1, r);
         t[x] = max(t[x * 2], t[x * 2 + 1]);
     }
      
     void update(int x, int l, int r, int std, int k)
     {
         if(std > r || std < l) return ;
         if(l >= r)
         {
             t[x] += k;
             return ;
         }
         update(x * 2, l, mid, std, k);
         update(x * 2 + 1, mid + 1, r, std, k);
         t[x] = max(t[x * 2], t[x * 2 + 1]); 
     }
      
     int main()
     {
         scanf("%d", &T);
         while(T--)
         {
             scanf("%d", &n);
             build(1, 1, n);
             fl = max_ = 1, fa[n + 1] = n + 1;
             for(int i = 1; i <= n; i++) 
             {
                 scanf("%d", &x);
                 a[x] = i; fa[i] = i;
                 cnt[i] = 1;
             }
             for(int i = 1; i <= n; i++)
             {
                 if(cnt[find(a[i])] != t[1])
                 {
                     fl = 0;
                     printf("No
    ");
                     break;
                 }
                 int x = find(a[i] + 1), y = find(a[i]);
                 if(x != n + 1) update(1, 1, n, x, cnt[y]);
                 update(1, 1, n, y, -cnt[y]);
                 cnt[x] += cnt[y];
                 cnt[y] = 0;
                 fa[y] = x;
             }
             if(fl == 1) printf("Yes
    ");
         }
         return 0;
     }
    

    A. Powered Addition

    题目链接

    (maxx[i]) 表示 (i) 前面(不含)(a[j]) 的最大值,(a[i]) 最小变为 (maxx[i])。因为它们的差恰好能被一些 (2) 的次方数唯一地凑出来,将它改正的时间就是其中的 (k),使 (2^k)(≤maxx[i]-a[i]) 的最大整数

     #include <iostream>
     #include <cstdio>
     #include <cstring>
     using namespace std;
     
     const int N = 233333;
     long long T, n, tot, ans, a[N], base[N], now;
     
     long long check(long long x)
     {
         for(int i = tot; i >= 0; i--)
             if(x >= base[i]) return i + 1;
     }
     
     int main()
     {
         scanf("%lld", &T);
         tot = -1;
         for(long long i = 1; i <= 2000000000; i *= 2)
             base[++tot] = i;
         while(T--)
         {
             scanf("%lld", &n);
             for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
             ans = 0, now = a[1];
             for(int i = 1; i <= n; i++)
             {
                 if(now > a[i])
                 {
                     ans = max(ans, check(now - a[i]));
                     a[i] = now;
                 }
                 now = max(now, a[i]);
             }
             printf("%lld
    ", ans);
         }
         return 0;
     }
    

    A. Linova and Kingdom

    题目链接

    先不考虑工业城市的放法,考虑旅游城市的放法。共需要放 (n-k) 个旅游城市,如果它的子树中所有节点都是工业城市,那么在 (i) 号放一个旅游城市带来的贡献是 (siz[i])(即以 (i) 为根的子树的大小)。如果它有 (x) 个祖宗(包括 (i) 自己),那么这些祖宗的贡献值都要被 (-1)

    因为在某个结点放旅游城市时,它的所有祖宗结点肯定已经全部变成了旅游城市,只要按照 (siz[i]-1-dep[i]) 排序即可(根节点的深度为 (0)

     #include <iostream>
     #include <cstdio>
     #include <cstring>
     #include <algorithm>
     using namespace std;
     
     const int N = 2333333;
     struct edge { int nxt, to; } e[N];
     struct srt { int id; long long val; } st[N];
     int n, k, a, b, cnt = 0, head[N], siz[N], dep[N];
     long long ans = 0;
     
     bool cmp(srt x, srt y) { return x.val > y.val; }
     
     void add(int x, int y)
     {
         e[++cnt] = (edge) { head[x], y };
         head[x] = cnt;
     }
     
     void dfs(int x, int fa)
     {
         siz[x] = 1;
         dep[x] = dep[fa] + 1;
         for(int i = head[x]; i; i = e[i].nxt)
         {
             int v = e[i].to;
             if(v == fa) continue;
             dfs(v, x);
             siz[x] += siz[v];
         }
     }
     
     int main()
     {
         scanf("%d%d", &n, &k);
         dep[0] = -1;
         memset(head, 0, sizeof(head));
         for(int i = 1; i < n; i++)
         {
             scanf("%d%d", &a, &b);
             add(a, b), add(b, a);
         }
         dfs(1, 0);
         for(int i = 1; i <= n; i++)
         {
             st[i].id = i;
             st[i].val = siz[i] - dep[i] - 1;
         }
         sort(st + 1, st + n + 1, cmp);
         for(int i = 1; i <= n - k; i++) ans += st[i].val;
         printf("%lld", ans);
         return 0;
     }
    

    C. Circle of Monsters *

    题目链接

    嗯看的官方题解 https://codeforces.com/blog/entry/75877

     #include <iostream>
     #include <cstdio>
     #include <cstring>
     #include <algorithm>
     using namespace std;
     
     const long long INF = 1e18;
     long long T, n, num, ans, a[2333333], b[2333333];
     
     int main()
     {
         scanf("%lld", &T);
         while(T--)
         {
             scanf("%lld", &n);
             num = 0, ans = INF;
             for(int i = 1; i <= n; i++)
                 scanf("%lld%lld", &a[i], &b[i]);
             for(int i = 1; i <= n; i++)
             {
                 int pre = i - 1;
                 if(i == 1) pre = n;
                 num += max(0ll, a[i] - b[pre]);
             }
             for(int i = 1; i <= n; i++)
             {
                 int pre = i - 1;
                 if(i == 1) pre = n;
                 ans = min(ans, num - max(0ll, a[i] - b[pre]) + a[i]);
             }
             printf("%lld
    ", ans);
         }
         return 0;
     }
    

    C. K-Complete Word *

    题目链接

    要想满足题面要求,字符串不仅本身是回文串,每 (k) 位也应该构成回文串。即求所有的 (i,k*j+i,k*j+k-i+1) 相等。对于每个 (i),在所有这些位置里面选出出现最多的字母,都更改为这个字母。

     #include <iostream>
     #include <cstdio>
     #include <cstring>
     using namespace std;
     
     const int N = 233333;
     int T, n, k, ans, num, max_, a[N], cnt[N];
     string s;
     
     int main()
     {
         scanf("%d", &T);
         memset(cnt, 0, sizeof(cnt));
         while(T--)
         {
             scanf("%d%d", &n, &k);
             cin >> s;
             ans = 0;
             for(int i = 0; i < n; i++) a[i + 1] = s[i];
             for(int i = 1; i <= k; i++)
             {
                 num = max_ = 0;
                 for(int j = 0; j * k + i <= n; j++)
                 {
                     cnt[a[j * k + i]]++;
                     cnt[a[j * k + k - i + 1]]++;
                     num += 2;
                     max_ = max(max_, cnt[a[j * k + i]]);
                     max_ = max(max_, cnt[a[j * k + k - i + 1]]);
                 }
                 for(int j = 0; j * k + i <= n; j++)
                 {
                     cnt[a[j * k + i]] = 0;
                     cnt[a[j * k + k - i + 1]] = 0;
                 }
                 ans += num - max_;
             }
             printf("%d
    ", ans / 2);
         }
         return 0;
     }
    

    B. Composite Coloring *

    题目链接

    看题解三连...

    每个合数 (x) 都能整除一个最小的质数,这个质数 (≤sqrt(x))。而 (sqrt(1000)) 以下正好有 (11) 个质数,所以直接把每个 (i) 分到它能整出的最小的质数组。

     #include <iostream>
     #include <cstdio>
     #include <cstring>
     using namespace std;
     
     const int N = 23333;
     int T, n, color, num[N], a[N], col[N];
     int p[] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31};
     
     int main()
     {
         scanf("%d", &T);
         while(T--)
         {
             scanf("%d", &n);
             color = 0;
             for(int i = 1; i <= 11; i++) num[i] = 0;
             for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
             for(int i = 1; i <= n; i++)
                 for(int j = 1; j <= 11; j++)
                     if(a[i] % p[j] == 0)
                     {
                         if(!num[j]) num[j] = ++color;
                         col[i] = num[j];
                         break;
                     }
             printf("%d
    ", color);
             for(int i = 1; i <= n; i++) printf("%d ", col[i]);
             printf("
    ");
         }
         return 0;
     }
    

    B. Dreamoon Likes Permutations

    题目链接

    如果一个区间有恰好 (m) 个元素,且这些元素的最大值是 (m),说明当前区间符合条件

    从前往后,从后往前分别记录 (1-i) 是否符合条件、(i-n) 是否符合条件,枚举断点判断即可

     #include <iostream>
     #include <cstdio>
     #include <cstring>
     using namespace std;
     
     const int N = 2333333;
     int T, n, ans, max_, num, a[N], t1[N], t2[N], p1[N], p2[N];
     
     int main()
     {
         scanf("%d", &T);
         while(T--)
         {
             scanf("%d", &n);
             ans = 0;
             for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
             for(int i = 1; i <= n; i++)
                 p1[i] = p2[i] = false, t1[a[i]] = t2[a[i]] = 0;
             max_ = num = 0;
             for(int i = 1; i <= n; i++)
             {
                 if(!t1[a[i]]) max_ = max(max_, a[i]), num++;
                 else break;
                 if(max_ == num) p1[i] = true;
                 t1[a[i]]++;
             }
             max_ = num = 0;
             for(int i = n; i > 0; i--)
             {
                 if(!t2[a[i]]) max_ = max(max_, a[i]), num++;
                 else break;
                 if(max_ == num) p2[i] = true;
                 t2[a[i]]++;
             }
             for(int i = 1; i < n; i++)
                 if(p1[i] && p2[i + 1]) ans++;
             printf("%d
    ", ans);
             for(int i = 1; i < n; i++)
                 if(p1[i] && p2[i + 1])
                     printf("%d %d
    ", i, n - i);
         }
         return 0;
     }
    

    C. Game with Chips

    题目链接

    有一种奇妙的构造方式,就是先向右移,把所有棋子都移到最后一列;然后都移到第一行。这时 (k) 个棋子变成了“一个棋子”。让这些棋子从右上角开始遍历整个棋盘。可以证明这种构造方式的路径总长度不会超过 (2mn)(因此不存在 (-1) 的情况)

     #include <iostream>
     #include <cstring>
     #include <cstdio>
     using namespace std;
     int T, n, m, k, x, y;
     int main()
     {
         scanf("%d%d%d", &n, &m, &k);
         for(int i = 1; i <= k * 2; i++) scanf("%d%d", &x, &y);
         printf("%d
    ", m + n + m * n - 1);
         for(int i = 1; i <= m; i++) printf("R");
         for(int i = 1; i <= n; i++) printf("U");
         for(int i = 1; i <= n; i++)
         {
             if(i % 2 == 0)
                 for(int j = 1; j < m; j++) printf("R");
             else for(int j = 1; j < m; j++) printf("L");
             if(i != n) printf("D");
         }
         return 0;
     }
    

    D1. Prefix-Suffix Palindrome (Easy version) *

    题目链接

    先判断最长有多长的前后缀相等,然后判断中间最长的回文串(左端点与最长前缀相连或右端点与最长的后缀相连)

     #include <iostream>
     #include <cstdio>
     #include <cstring>
     #include <algorithm>
     using namespace std;
     
     const int N = 233333;
     int T, n, l, r, l1, l2, tag, a1, a2, a[N];
     string s, ans;
     
     bool check(int x, int y)
     {
         while(a[x] == a[y] && x <= n && y > 0) x++, y--;
         return x >= y;
     }
     
     int main()
     {
         scanf("%d", &T);
         while(T--)
         {
             cin >> s; n = s.size();
             for(int i = 1; i <= n; i++) a[i] = s[i - 1];
             if(n == 1 || check(1, n)) { cout << s << "
    "; continue; }
             l = 1, r = n;
             while(a[l] == a[r]) l++, r--;
             ans = "", a1 = l, a2 = r;
             for(int i = l; i <= r; i++) if(check(l, i)) a1 = i;
             for(int i = r; i >= l; i--) if(check(i, r)) a2 = i;
             if(a1 - l >= r - a2)
             {
                 for(int i = 1; i <= a1; i++) ans += a[i];
                 for(int i = r + 1; i <= n; i++) ans += a[i];
             }
             else
             {
                 for(int i = 1; i < l; i++) ans += a[i];
                 for(int i = a2; i <= n; i++) ans += a[i];
             }
             cout << ans << endl;
         }
         return 0;
     }
    

    C. Ehab and Path-etic MEXs

    题目链接

    为了不让大权值成为路径上的“最小的未出现”,需要尽量让它出现在路径上。经过某条边的路径数 (val[i]=siz[i]*(n-siz[i]))(siz[i]) 表示 (i) 边向下的子树大小)。将边按照 (val) 从大到小排序,(val) 大的边放大的权值

     #include <iostream>
     #include <cstdio>
     #include <cstring>
     #include <algorithm>
     #define LL long long
     using namespace std;
     
     const int N = 233333;
     struct edge { LL nxt, to, val, id; } e[N];
     LL n, a, b, cnt = 0, head[N], ans[N], siz[N];
     
     void add(LL x, LL y)
     {
         e[++cnt] = (edge) { head[x], y, 0, cnt };
         head[x] = cnt;
     }
     
     void dfs(LL x, LL fa)
     {
         siz[x] = 1;
         for(int i = head[x]; i; i = e[i].nxt)
         {
             LL v = e[i].to;
             if(v == fa) continue;
             dfs(v, x);
             siz[x] += siz[v];
             e[i].val = siz[v] * (n - siz[v]);
         }
     }
     bool cmp(edge x, edge y) { return x.val > y.val; }
     
     int main()
     {
         scanf("%lld", &n);
         memset(ans, -1, sizeof(ans));
         for(int i = 1; i < n; i++)
         {
             scanf("%lld%lld", &a, &b);    
             add(a, b); add(b, a);
         }
         dfs(1, 0);
         sort(e + 1, e + cnt + 1, cmp);
         for(int i = 1; i < n; i++)
             ans[e[i].id] = n - 2 - i + 1;
         for(int i = 1; i <= cnt; i++)
             if(ans[i] != -1) printf("%lld
    ", ans[i]);
         return 0;
     }
    

    D. Pair of Topics

    题目链接

    为了使 (i)(j) 都在一边,把这个式子移项:(a[i]-b[i]=-a[j]+b[j])。先按照 (-a[i]+b[i]) 排序,对于每个 (i) 进行二分查找,统计答案。

     #include <iostream>
     #include <cstdio>
     #include <cstring>
     #include <algorithm> 
     #define LL long long
     using namespace std;
     
     const int N = 233333;
     struct edge { LL a, b; } e[N];
     LL n, ans = 0;
     bool cmp(edge x, edge y) { return x.b - x.a < y.b - y.a; }
     
     LL check(LL x)
     {
         LL l = 0, r = n;
         while(l + 1 < r)
         {
             LL mid = (l + r) >> 1;
             if(e[mid].b - e[mid].a < x) l = mid;
             else r = mid;
         }
         if(e[r].b - e[r].a < x) return r;
         return l;
     }
     
     int main()
     {
         scanf("%lld", &n);
         for(int i = 1; i <= n; i++) scanf("%lld", &e[i].a);
         for(int i = 1; i <= n; i++) scanf("%lld", &e[i].b);
         sort(e + 1, e + n + 1, cmp);
         for(int i = 1; i <= n; i++)
             ans += check(e[i].a - e[i].b);
         for(int i = 1; i <= n; i++)
             if(e[i].a * 2 > e[i].b * 2) ans--;
         printf("%lld", ans / 2);
         return 0;
     }
    

    B. Count Subrectangles

    题目链接

    稍加观察可以发现,(a) 中任何一段连续的 (1)(b) 中任何一段连续的 (1) 都可以组成一个矩阵。那么对于每一段连续的 (1),我们都只关心它的长度,而不关心它的位置。可以利用差分统计一下每个长度都出现了几次,选择能被 (k) 整除的 (i) 统计答案

     #include <iostream>
     #include <cstdio>
     #include <cstring>
     using namespace std;
     
     const int N = 500000;
     long long n, m, k, len, ans = 0, a, b, p1[N], p2[N];
     
     int main()
     {
         scanf("%lld%lld%lld", &n, &m, &k);
         len = 0;
         memset(p1, 0, sizeof(p1));
         memset(p2, 0, sizeof(p2));
         for(int i = 1; i <= n; i++)
         {
             scanf("%lld", &a); 
             if(a == 0) len = 0;
             else len++;
             p1[1]++, p1[len + 1]--;
         }
         len = 0;
         for(int i = 1; i <= m; i++)
         {
             scanf("%lld", &b);
             if(b == 0) len = 0;
             else len++;
             p2[1]++; p2[len + 1]--;
         }
         for(int i = 1; i <= n; i++) p1[i] += p1[i - 1];
         for(int i = 1; i <= m; i++) p2[i] += p2[i - 1];
         for(int i = 1; i <= n; i++)
             if(k % i == 0 && k / i <= m)
                 ans += p1[i] * p2[k / i];
         printf("%lld", ans);
         return 0;
     }
    

    C. Remove Adjacent *

    题目链接

    每次选择一个最大能删除的字母删除,因为它不会影响其他字母的删除。证明如下:

    (1.) 序列中不存在字母比它大,删它肯定不影响

    (2.) 序列中存在字母比它大,中间没隔着任何字母。这种情况实际上不存在,因为这种情况下这个字母不是最大可删除的字母

    (3.) 序列中存在字母比他大,中间隔着一些字母,可以证明中间的字母不可能删干净。

     #include <iostream>
     #include <cstdio>
     #include <cstring>
     using namespace std;
     
     const int N = 2333;
     int n, ans = 0, a[N], del[N];
     string s;
     
     int get(int x, int k)
     {
         int tot = 0;
         if(k < 0)
         {
             for(int i = x - 1; i > 0; i--)
                 if(del[i] == false) return a[i];
             return 0x3f3f3f3f;
         } 
         for(int i = x + 1; i <= n; i++)
             if(del[i] == false)    return a[i];
         return 0x3f3f3f3f;
     }
     
     int main()
     {
         scanf("%d", &n);
         cin >> s;
         memset(a, 0x3f, sizeof(a));
         memset(del, false, sizeof(del));
         for(int i = 1; i <= n; i++) a[i] = s[i - 1];
         while(true)
         {
             int max_ = 0, id = -1;
             for(int i = 1; i <= n; i++)
                 if(!del[i] && (get(i, -1) == a[i] - 1 || get(i, 1) == a[i] - 1))
                     if(a[i] > max_) max_ = a[i], id = i;
             if(id == -1) break;
             del[id] = true;
         }
         for(int i = 1; i <= n; i++) if(del[i]) ans++;
         printf("%d", ans);
         return 0;
     }
    

    A. Journey Planning

    题目链接

    将这个式子移项得:(i-b[i]=j-b[j])。设 (val[i]=i-b[i]),按照 (val) 为排序。对于每一个 (val),统计所有 (val) 值相等的数的和,在里面取最大值作为答案

     #include <iostream>
     #include <cstdio>
     #include <cstring>
     #include <algorithm>
     using namespace std;
     
     const int N = 2333333;
     struct node { long long id, b, val; } a[N];
     long long n, ans = 0, sum = 0;
     bool cmp(node x, node y)
     {
         return x.b == y.b ? x.id < y.id : x.val < y.val;
     }
     
     int main()
     {
         scanf("%lld", &n);
         for(int i = 1; i <= n; i++)
         {
             scanf("%lld", &a[i].b);
             a[i].id = i;
             a[i].val = a[i].id - a[i].b;
         }
         sort(a + 1, a + n + 1, cmp);
         for(int i = 1; i <= n; i++)
         {
             if(a[i].val != a[i - 1].val || i == 1)
             {
                 ans = max(ans, sum);
                 sum = a[i].b;
             }
             else sum += a[i].b;
         }
         printf("%lld", max(ans, sum));
         return 0;
     }
    

    B. String Modification *

    题目链接

    (*1400) 还要看题解的垃圾的我...

    所以不写辣,甩上题解(逃 https://codeforces.com/blog/entry/74493

     #include <iostream>
     #include <cstdio>
     #include <cstring>
     using namespace std;
     
     const int N = 233333;
     int T, n, id, a[N];
     string s;
     
     int get(int x, int pos)
     {
         if(pos <= n - x + 1) return a[pos + x - 1];
         if((n % 2) == (x % 2)) return a[x - (pos - (n - x + 1))];
         return a[pos - n + x - 1];
     }
     
     int main()
     {
         scanf("%d", &T);
         while(T--)
         {
             scanf("%d", &n);
             cin >> s;
             id = 1;
             for(int i = 1; i <= n; i++) a[i] = s[i - 1];
             for(int i = 2; i <= n; i++)
                 for(int j = 1; j <= n; j++)
                 {
                     if(get(i, j) < get(id, j))
                     {
                         id = i;
                         break;
                     }
                     if(get(i, j) > get(id, j)) break;
                 }
             for(int j = 1; j <= n; j++) cout << (char)(get(id, j));
             printf("
    %d
    ", id);
         }
     }
    

    其实后面还做过一些,现在开学了,就先鸽着吧...

  • 相关阅读:
    04_Windows平台Spark开发环境构建
    Hadoop Streaming 使用及参数设置
    Kafka 及 PyKafka 的使用
    Database Subquery
    Miscellaneous
    Emacs
    算法归纳
    逆元求组合数
    Elasticsearch 原理
    Linux的内存分页管理【转】
  • 原文地址:https://www.cnblogs.com/Andy-park/p/12850417.html
Copyright © 2020-2023  润新知