三十年河东,三十年河西|

自动机

园龄:1年10个月粉丝:2关注:4

Codeforces Round 889 (Div. 2)

B

题意:

给你一个正整数n,要你求一个最长的区间[l, r]使得区间中的每个数都是n的约数(n <= 1018),输出区间长度

思路:

暴力:直接两重循环枚举区间左右端点,时间复杂度O(n2)显然是无法接受的。于是换个角度先预处理出来所有的约数再双指针求连续上升的最长一段,时间复杂度O(n+n)还是不能接受
这时候怎么办呢?可根据数学性质直接暴力

#include <bits/stdc++.h>

using namespace std;
#define more ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
const int N = 2e5 + 5, MOD = 1e9 + 7;
const long long INF = 1e18;
typedef long long LL;
typedef unsigned long long usLL;
typedef pair<int, int> PII;

void solve()
{
    LL n; cin >> n;
    std::vector<int> a;
    for (int i = 1; i; i++)
    {
        if (n % i == 0) a.push_back(i);
        else break;
    }
    cout << a.size() << endl;
}

int main()
{
    more;
    int T;
    cin >> T;
    while (T--)
    {
        solve();
    }
    //solve();
    return 0;
}

D

题意:

你有一叠牌一共n张,每次你可以从牌堆顶部拿一张未解锁的牌出来,这张牌的点数为x,你有两种选择

  1. 将这张牌收入囊中并获得x
  2. 消耗这张牌解锁这张牌后面未解锁的x张牌
    初始时最上面一张牌是解锁的,问你最多可以获得多少点数

思路:

赛时没思路。。。
如果我们知道了最后一张解锁的牌的下标j,那么我们可获得的点数为i=0jai(j1),因为前j张牌我们都可以选它们的点数和减去解锁j张牌所需要的点数就是我们获得的点数
那么要如何知道我们最后一张牌在哪呢?可以把整个牌堆看成一个二进制数,二进制为1说明这个位置可以作为最后一张牌,怎么求呢?看代码

void solve() 
{
    int n; cin >> n;
    std::vector<int> a(n + 1);

    bitset<N> b; // 默认从右往左,下标从0开始

    for (int i = 1; i <= n; i++)
        cin >> a[i];

    b[1] = 1;
    for (int i = 1; i <= n; i++) // 预处理, 当前已经处理到i,说明i以前都用了没贡献了所以左移掉,然后再右移a[i]位把我能影响的最后一位显示出来但是要加上i,保证对齐
        b |= (b >> i) << (i + a[i]);

    LL sum = 0, ans = -INF;
    for (int i = 1; i < N; i++)
    {
        if (i <= n) sum += a[i];
        if (b[i]) // 当前位可能是最后一位
        {
            ans = max(ans, sum - (i - 1));
        }
    }

    cout << ans << endl;
}

本文作者:自动机

本文链接:https://www.cnblogs.com/monituihuo/articles/17592443.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   自动机  阅读(8)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起