对于长度为
对于正整数
给你一个长度为
很头疼的一个东西。
树状数组的结构如下:
乍一看无从下手,
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
int k;
>> k;
cin for (int i = 1; i <= 8; i++)
<< a[i] << " ";
cout << endl;
cout while (k--)
{
for (int i = 1; i <= 7; i++)
[8] += a[i];
a[6] += a[5];
afor (int i = 1; i <= 3; i++)
[4] += a[i];
a[2] += a[1];
afor (int i = 1; i <= 8; i++)
<< a[i] << " ";
cout << endl;
cout }
("pause");
system}
模拟结果如下:
1 2 3 4 5 6 7 8
1 3 3 10 5 11 7 36
1 4 3 17 5 16 7 76
1 5 3 25 5 21 7 129
观察贡献情况,发现以下特点:
对于25
而言,其是由1
贡献6次,2
和3
贡献3次,4
贡献1次而来的。
这是一个多重前缀和的贡献
1 1 1 1 1 1 1 1
1 2 3 4 5 6 7 8
1 3 6 10 15 21 28 36
1 4 10 16 26 41 62 90
讨论129
129
中,1
贡献距离为2
贡献距离为
3
为4
为5
为6
为7
为8
为
问题在于如何维护贡献系数。
j 0 1 2 3 4 5 6 7
i=0 1 1 1 1 1 1 1 1
i=1 1 2 3 4 5 6 7 8
i=2 1 3 6 10 15 21 28 36
i=3 1 4 10 20 35 56 84 120
然后注意到一个问题就是
注意到
之前已经讨论过了阶乘线性递推的逆元解法,但是这里要求的不是线性阶乘的逆元。
递推方式如下:
[0]=inv[1]=1;
inv= maxn - 1;
n for (int i=2;i<=n;i++) inv[i] = (mod-mod/i)*inv[mod%i]%mod;
然后暴力树状数组就行了。
#include <bits/stdc++.h>
using namespace std;
using p = pair<int, int>;
#define IOS \
ios::sync_with_stdio(false); \
cin.tie(nullptr); \
cout.tie(nullptr);
#define int long long
const int INF = 1e18;
const int mod = 998244353;
const int maxn = 2e5 + 1;
#define lowbit(x) (x & -x)
int inv[51];
int quickpow(int a, int b)
{
int e = 1;
while (b)
{
if (b & 1)
(e *= a) %= mod;
(a *= a) %= mod;
>>= 1;
b }
return e;
}
int quickinv(int a)
{
return quickpow(a, mod - 2);
}
int n, k;
int num[51];
void init()
{
[0] = inv[1] = 1;
invfor (int i = 2; i <= 50; i++)
{
[i] = (mod - mod / i) * inv[mod % i] % mod;
inv}
}
void solve()
{
>> n >> k;
cin <int> a(n + 1);
vectorfor (int i = 1; i <= n; i++)
{
>> a[i];
cin }
for (int i = 1; i <= 50; i++)
{
int mul = 1;
[i] = 1;
numfor (int j = 1; j <= i; j++)
{
(num[i] *= (j + k - 1)) %= mod;
(num[i] *= inv[j]) %= mod;
}
}
for (int i = 1; i <= n; i++)
{
int depth = 0;
for (int j = i + lowbit(i); j <= n && j != i; j += lowbit(j))
{
++;
depth[j] = (a[j] - (a[i] * num[depth] % mod) + mod) % mod;
a}
}
for (int i = 1; i <= n; i++)
{
<< a[i] << " ";
cout }
<< endl;
cout return;
}
signed main()
{
;
IOSint t;
();
init>> t;
cin while (t--)
{
();
solve}
("pause");
systemreturn 0;
}
两个版本的问题不同。您可能需要同时阅读两个版本。只有两个版本的问题都解决了,您才能进行Hack。
给你两个正整数
计算满足以下条件的有序数对
数学题。
简单版本显然有
讨论困难版本。
显然有
所以必然有
注意到
时间复杂度
#include <bits/stdc++.h>
using namespace std;
using p = pair<int, int>;
#define IOS \
ios::sync_with_stdio(false); \
cin.tie(nullptr); \
cout.tie(nullptr);
#define int long long
const int INF = 1e18;
const int mod = 998244353;
int n, m;
void solve()
{
>> n >> m;
cin int ans = 0;
for (int i = 1; i * i < n; i++)
{
for (int j = 1; j * j < m; j++)
{
if (__gcd(i, j) == 1)
{
+= min((n / i) / (i + j), (m / j) / (i + j));
ans }
}
}
<< ans << endl;
cout return;
}
signed main()
{
;
IOSint t;
>> t;
cin while (t--)
{
();
solve}
("pause");
systemreturn 0;
}
你有几张牌。每张卡片上都写着一个介于
还有一个商店,里面有无限量的各种类型的卡片。你有
购买新牌后,您要将所有牌重新排列成一行。重新排列的得分是长度为
根据样例不难想到要把完整的套牌全部挑出来然后排成排列序。
限制因素是最少的牌,我们可以补充最少的牌来增加完整套牌的总数。答案具有单调性,可以二分答案。
得到完整套牌的最大值之后,剩余的牌如何处理?实际上,必然有一种排列方式能使得剩下的这些牌种类无论以什么顺序跟在完整套牌群的末尾,都能继续构成新的排列。
(显然,通过这些剩下的牌定排列顺序就行了)
比如说完整套牌为12345,你现在剩下了1 1 3 5,总计三种牌。那么就可以有一个排列顺序为13524,使得135能够跟在前序完整套牌组的后面,再延伸三种满足的条件:
再剩下的
然后,如果你手里还有可以购买的e额度,就继续延伸答案即可。
#include <bits/stdc++.h>
using namespace std;
using p = pair<int, int>;
#define IOS \
ios::sync_with_stdio(false); \
cin.tie(nullptr); \
cout.tie(nullptr);
#define int long long
const int INF = 1e18;
const int mod = 998244353;
<int> a;
vectorint n, k;
bool check(int x)
{
int now = k;
for (int i = 1; i <= n; i++)
{
if (a[i] < x)
-= (x - a[i]);
now if (now < 0)
return false;
}
return true;
}
void solve()
{
>> n >> k;
cin = vector<int>(n + 1);
a for (int i = 1; i <= n; i++)
>> a[i];
cin if (n == 1)
{
<< a[1] + k << endl;
cout return;
}
int l = 0, r = 1e18 + 1;
while (l < r)
{
int mid = (l + r) >> 1LL;
if (check(mid))
= mid;
l else
= mid;
r }
for (int i = 1; i <= n; i++)
{
if (a[i] < l)
-= (l - a[i]);
k }
int pos;
int ans = (l - 1) * n + 1;
for (int i = 1; i <= n; i++)
{
if (a[i] > l)
++;
ans}
+= k;
ans << ans << endl;
cout }
signed main()
{
;
IOSint t;
>> t;
cin while (t--)
{
();
solve}
("pause");
systemreturn 0;
}
桌子上有
在每次操作中,玩家选择一枚正面朝上的硬币,取出硬币并翻转与其相邻的两枚硬币。如果(操作前)只剩下两枚硬币,则取出一枚,另一枚不翻转(因为会翻转两次)。如果(操作前)只剩下一枚硬币,则不会翻转任何硬币。如果(操作前)没有正面朝上的硬币,玩家就输了。
如果两人都以最佳方式下棋,谁会赢呢?可以证明,游戏将在有限次的操作中结束,其中一人将获胜。
当
假定序列里全是
可以推出,
考虑所有可能的操作:
每一次操作,序列中
故猜测
嗯,就硬猜。
#include <bits/stdc++.h>
using namespace std;
using p = pair<int, int>;
#define IOS \
ios::sync_with_stdio(false); \
cin.tie(nullptr); \
cout.tie(nullptr);
#define int long long
const int INF = 1e18;
const int mod = 998244353;
void solve()
{
int n;
>> n;
cin ;
string s>> s;
cin int ans = 0;
bool flag = false;
for (auto p : s)
{
^= (p == 'U');
flag }
if (flag)
<< "Yes" << endl;
cout else
<< "No" << endl;
cout return;
}
signed main()
{
;
IOSint t;
>> t;
cin while (t--)
{
();
solve}
("pause");
systemreturn 0;
}
请我喝杯咖啡吧~