嘘~ 正在从服务器偷取页面 . . .

洛谷P6015 [CSGRound3]游戏 题解


洛谷P6015 [CSGRound3]游戏 题解

题目链接:P6015 [CSGRound3]游戏

题意

小 Y 和小 Z 是一对好朋友,他们在玩一个游戏。游戏只有一个回合

有一个牌堆,一共有 \(n\) 张牌,第 \(i\) 张牌上有一个数 \(a_i\),其中第一张牌是堆顶。

小 Z 先取牌,他可以从堆顶开始取连续若干张牌(可以取 \(0\)),取完的牌拿在手上,也就是不在牌堆里了。

然后小 Y 取牌,同样,她也可以从堆顶开始取连续若干张牌(可以取 \(0\))。

如果一个人手上的牌的数字和大于 \(X\),那么他的分数就是 \(0\),否则分数就是数字和。

分数高的人获胜,如果一样高,则无人获胜

小 Z 为了获胜,使用了透视挂,即他知道牌堆里每张牌上写的数。

现在问你对于满足 \(1 \leq X \leq K\) 的所有整数 \(X\),哪些可以使得小 Z 有必胜策略,即小 Z 取完后,不管小 Y 怎么取都一定会

输入格式

第一行一个整数 \(n\),表示牌堆里有几张牌。

第二行 \(n\) 个整数 \(a_{1\dots n}\),表示每张牌上写的数。

第三行一个正整数 \(K\),含义见题目描述。

输出格式

第一行一个整数,表示满足要求的 \(X\) 的个数。

第二行从小到大依次输出满足要求的 \(X\),用空格隔开。

数据范围

对于 \(100\%\) 的数据,\(1\leq n,K \leq 10^6\)\(1\leq a_i \leq K\)

\(S_i = \sum _{ j = 1} ^ {i} a_j\)\(p\) 为所有满足 \(S_p - S_i \ge S_i\) 的正整数中最小的一个。

则所有 \(X \in \left[S_i, ~S_p - S_i\right)\) 均必胜。则最终答案为所有区间的并。

显然 \(p\) 单调不降,因此我们可以以双指针的形式维护它。

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

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(1e6 + 15))

vector<int> vec;
int n,k,p,X[N * 2 + 15],sum[N];
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n;
    for(int i = 1; i <= n; i++) { cin >> sum[i], sum[i] += sum[i - 1]; }
    cin >> k;
    for(int i = 0; i <= n; i++)
    {
        if(sum[i] > k) break;
        for(; p <= n && sum[p] < sum[i] * 2; ++p) {;}
        ++X[sum[i]]; if(p <= n) --X[sum[p] - sum[i]];
    }
    for(int i = 1; i <= k; i++) {
        if(X[i] += X[i - 1]) vec.emplace_back(i);
    }
    cout << vec.size() << '\n'; for(auto i : vec) cout << i << ' ';
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录