Codeforces Round 889 (Div. 2)
B
题意:
给你一个正整数n,要你求一个最长的区间[l, r]使得区间中的每个数都是n的约数(n <= $ 10^{18} $),输出区间长度
思路:
暴力:直接两重循环枚举区间左右端点,时间复杂度O(\(n^2\))显然是无法接受的。于是换个角度先预处理出来所有的约数再双指针求连续上升的最长一段,时间复杂度O(\(\sqrt{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,你有两种选择
- 将这张牌收入囊中并获得
x点 - 消耗这张牌解锁这张牌后面未解锁的
x张牌
初始时最上面一张牌是解锁的,问你最多可以获得多少点数
思路:
赛时没思路。。。
如果我们知道了最后一张解锁的牌的下标j,那么我们可获得的点数为\(\displaystyle\sum_{i=0}^ja_i - (j - 1)\),因为前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;
}

浙公网安备 33010602011771号