首页 > 其他分享 >Solution - Atcoder AGC022D Shopping

Solution - Atcoder AGC022D Shopping

时间:2024-07-14 20:34:02浏览次数:12  
标签:Atcoder Shopping int 2x vis AGC022D && 2L id

考虑到不管怎么走,都是 \(0\) 最后又绕回 \(0\),于是答案肯定是 \(2L\) 的倍数。
那么考虑 \(\frac{\operatorname{ans}}{2L}\) 即可。

那么对于 \(t_i\),可以先让答案加上 \(\lfloor\frac{t_i}{2L}\rfloor\),同时令 \(t_i\leftarrow t_i \bmod 2L\)。
原因就是考虑到这被去除掉的 \(2L\) 肯定是转的完整的一圈,没有什么影响。
那么剩下的 \(t_i\) 就满足 \(t_i\in [0, 2L)\) 了。

接下来考虑对于这部分 \(t_i\) 怎么做。
首先有一个很显然的上界,从左往右,对于每个 \(i\) 都转一圈,那么一共就有 \(n\) 圈,还加上 \(0\) 到 \(0\) 的 \(1\) 圈,共 \(n + 1\) 圈。

考虑从这个上界往下减小。

首先如果有 \(t_i = 0\),明显不用多转一圈了,就可以 \(-1\)。

接下来考虑到其实转一圈有点浪费,可能转不满一圈那就肯定贪心的不会让其转满。
于是令 \(l_i, r_i\) 分别代表对于 \(i\) 能不能从左边 / 右边进入且出来时朝着这个方向,用式子表示就是 \(l_i = [2(L - x_i)\ge t_i], r_i = [2x_i\ge t_i]\),可能式子还清晰一些。

那么对于 \(n\),因为其是最后一个,那么若 \(l_n = 1\),那么就不用多转一圈了,就可以 \(-1\)。
同时对于 \(1\le i < j < n, r_i = 1, l_j = 1\),那就可以考虑先不走 \(i\),而是先走过 \(j\) 再走 \(i\) 绕回来,能发现这样子同样是 \(1\) 圈却走完了 \(2\) 个,也可以 \(-1\)。

那么接下来就解决这种情况。
首先 \((l_i, r_i) = (0 / 1, 0 / 1)\),对于 \((0, 0)\) 没用显然可以直接排除掉。
那么接下来的配对就只有可能是 \(((l_i, r_i), (l_j, r_j)) = ((1, 1), (1, 1)) / ((0, 1), (1, 1)) / ((1, 1), (1, 0)) / ((0, 1), (1, 0))\) 了。
再进一步考虑,能发现若 \((l_i, r_i) = (0, 1)\) 意味着 \(2x_i\ge t_i, 2L - 2x_i < t_i\),就有 \(2x_i\ge t_i, 2x_i > 2L - t_i\),所以 \(2x_i\ge \max\{t_i, 2L - t_i + 1\} = L + 1\);同理,能得到对于 \((l_i, r_i) = (1, 0)\) 有 \(2x_i\le L - 1\)。
那么就可以知道不可能存在 \(i < j, ((l_i, r_i), (l_j, r_j)) = ((0, 1), (1, 0))\) 的情况。

所以就只有前三种情况了。
能发现 \((1, 1)\) 可以算作万能的,所以先去贪心的匹配 \(((0, 1), (1, 1)), ((1, 1), (1, 0))\),最后再处理 \(((1, 1), (1, 1))\) 即可。

时间复杂度 \(\mathcal{O}(n)\)。

#include<bits/stdc++.h>
using ll = long long;
const int maxn = 3e5 + 10;
ll x[maxn], t[maxn];
int l[maxn], r[maxn];
bool vis[maxn];
int main() {
   int n; ll L;
   scanf("%d%lld", &n, &L);
   for (int i = 1; i <= n; i++) scanf("%lld", &x[i]);
   for (int i = 1; i <= n; i++) scanf("%lld", &t[i]);
   ll ans = n + 1;
   for (int i = 1; i <= n; i++)
      ans += t[i] / (2 * L), t[i] %= (2 * L);
   for (int i = 1; i <= n; i++)
      if (! t[i])
         vis[i] = 1, ans--;
   for (int i = 1; i <= n; i++)
      l[i] = (L - x[i]) * 2 >= t[i], r[i] = x[i] * 2 >= t[i];
   if (! vis[n])
      vis[n] = 1, ans -= l[n];
   std::vector<int> id;
   for (int i = 1; i < n; i++)
      if (! vis[i]) {
         if (! l[i] && r[i])
            id.push_back(i);
         if (l[i] && r[i] && id.size()) {
            int j = id.back(); id.pop_back();
            vis[i] = vis[j] = 1, ans--;
         }
      }
   id.clear();
   for (int i = n - 1; i; i--)
      if (! vis[i]) {
         if (! r[i] && l[i])
            id.push_back(i);
         if (l[i] && r[i] && id.size()) {
            int j = id.back(); id.pop_back();
            vis[i] = vis[j] = 1, ans--;
         }
      }
   for (int i = 1, j = -1; i < n; i++)
      if (! vis[i] && l[i] && r[i]) {
         if (~ j) vis[i] = vis[j] = 1, j = -1, ans--;
         else j = i;
      }
   printf("%lld\n", ans * 2 * L);
   return 0;
}

标签:Atcoder,Shopping,int,2x,vis,AGC022D,&&,2L,id
From: https://www.cnblogs.com/rizynvu/p/18301934

相关文章

  • Toyota Programming Contest 2024#7(AtCoder Beginner Contest 362)
    这场比赛还是比较水的A,B,C跳过D题dij把点权和边权都转换为边权即可E题DP可以用\(map\)存一下等差数列的差先说\(O(n^4)\),\(f_{len,i,j,t}\)分别表示长度,现在在\(i\),上一个在\(j\)显然动态转移方程就有了\(f_{len,i,j,k}=\sum_{k=1}^{k=j-1}f_{len-1,j,k,t}\)点击查看......
  • AtCoder Beginner Contest 362 补题记录(A~E,G)
    A分三类情况讨论即可。voidsolveqwq(){intr=io.read(),g=io.read(),b=io.read();stringqwq=io.readstring();if(qwq=="Blue")printf("%lld\n",min(r,g));elseif(qwq=="Red")printf("%lld\n",......
  • Solution - Atcoder AGC021D Reversed LCS
    考虑到\(\operatorname{LCS}(T,T')\)这个形式实在是不太优美,考虑转化一下形式。感受一下,能够知道\(T\)的最长回文子序列\(|\operatorname{LPS}(T)|=|\operatorname{LCS}(T,T')|\)。具体证明可以见zhihu,本人暂时还没看懂。那么接下来对于单个串的\(\operatorname{LPS......
  • Solution - Atcoder ARC127E Priority Queue
    考虑转化一下,每个最后留下来的集合都相对的对应着一个被删除的集合。于是考虑去对被删除的数去计数。然后贪心的,去让每一次\(2\)操作删除的数都是前面加入中还剩下的最后加入的数(因为有的可能被前面的\(2\)操作删了)。对于证明,考虑到如果不是剩下的最后加入的,那么中间可能会......
  • 【atcoder】习题——位元枚举
    题意:求i&M的popcount的和,i属于0……N主要思路还是变加为乘。举个例子N=22,即10110假设M的第3位是1,分析N中:00110001110010000101发现其实等价于0010001100000001也就是左边第4位和第5位不变,右边第1位和第2位不变拼接起来,相当于0000~001101110011110110001101......
  • Solution - Atcoder ABC177F I hate Shortest Path Problem
    考虑按题目所述的进行DP。设计状态\(f_{i,j}\)代表强制要求\((i,j)\)要走向\((i+1,j)\)最小的横坐标之差,这是因为对应的纵坐标之差是确定的。对于转移,考虑到对于\(j\not\in[a_i,b_i]\),直接从上面转移下来即可,即\(f_{i,j}\leftarrowf_{i-1,j}\)。对于\(j......
  • Solution - Atcoder ARC150D Removing Gacha
    考虑到每次操作都比定会选上一个点,于是答案可以表示为每个点被选中的次数之和。即令\(c_i\)为\(i\)点被选中的次数,答案即为\(E(\sum\limits_{i=1}^nc_i)\)。根据期望的线性性,考虑把答案的\(E\)拆到每个\(c_i\)上,即变为\(\sum\limits_{i=1}^nE(c_i)\)的形式。......
  • Denso Create Programming Contest 2024(AtCoder Beginner Contest 361)E-F
    E求一条树上的路径,使得走遍整棵树花费最小。我们容易发现树上的某条简单路径只需走一次,除此之外所有的路径都需要走两次,那么显而易见,我们需要求树的直径,之后将剩余的路径权值和乘二加上直径权值就可以。F数学题,对于数学题而言,个人感觉时间复杂度的计算对于题目的求解非常重......
  • AtCoder Beginner Contest 361
    AtCoderBeginnerContest361A-Insert给定一个长度为\(N\)的序列\(A\),现在希望将数字\(X\)插入到序列的第\(K\)个数字后面,变成一个新的序列\(B\)。输出序列\(B\)。\(K,N,A_i,X\le100\)模拟题。先读入\(N,K,X\)。接着在读入\(A\)的过程中一遍读入一遍输出,如果读到了第\(K......
  • AtCoder Beginner Contest 361)
    推荐个C++编程仓库模板https://github.com/yxc-s/programming-templateA-Insertvoidsolve(){ intn,k,x; cin>>n>>k>>x; vector<int>a(n); for(auto&x:a){ cin>>x; } a.insert(a.begin()+k,x); for(inti=0;......