2022.8.12 颓废记录
作者:互联网
Preface
不想开学 QAQ。
Content
[CF1252K]Addition Robot
挺新鲜的一道题,题解
[CF665E]Beautiful Subarrays
给定 \(a_{1\sim n}\),求满足 \(\bigoplus\limits_{i=l}^{r} a_i \ge k\) 的 \([l,r]\) 的数量。
\(1\le n\le 10^6,1\le a_i,k\le 10^9\)。
一眼题,把前缀和扔字典树里计算即可。时间复杂度 \(O(n\log k)\)。
Code
// Problem: CF665E Beautiful Subarrays
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF665E
// Memory Limit: 500 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
const int maxk = 30;
int trie[maxn * maxk][2],sum[maxn * maxk],rt,sz,n,k,cur;
void insert(int x) {
int u = rt;
++ sum[u];
for(int i = 29;~ i;-- i) {
int c = x >> i & 1;
if(!trie[u][c])trie[u][c] = ++ sz;
++ sum[u = trie[u][c]];
}
return ;
}
int query(int x) {
int ans = 0,u = rt,p = 0;
for(int i = 29;~ i;-- i) {
if(!u)break ;
int c = x >> i & 1;
if(k >> i & 1) {
u = trie[u][c ^ 1];
}
else {
ans += sum[trie[u][c ^ 1]];
u = trie[u][c];
}
}
return ans + sum[u];//equal
}
int main() {
rt = ++ sz;
scanf("%d %d",&n,&k);
insert(cur);
long long cnt = 0;
for(int i = 1,x;i <= n;++ i) {
scanf("%d",&x);
cur ^= x;
cnt += query(cur);
insert(cur);
}
printf("%lld\n",cnt);
return 0;
}
[CF103D]Time to Raid Cowavans
给定 \(a_{1\sim n}\),\(m\) 次询问,每次求出 \(a_{t}+a_{t+k}+a_{t+2k}+\ldots a_{t+pk}(t+(p+1)k\gt n)\)。
\(1\le n,m \le 3\times 10^5,1\le a_i\le 10^9,1\le t,k\le n\)。
不难发现这是一道根号分治题,但原题 \(68\rm{MB}\) 的空间很让人头疼。
哈希冲突这道题中,由于是全局询问,所以空间没有问题。
但现在引入了 \(t\),就需要 \(O(n\sqrt{n})\) 的空间,肯定过不了。
由于这题不需要修改,考虑离线,按 \(t\) 升序排序。
我本来想用 std::unordered_map
存一下跑记忆化搜索,这样理论上是 \(O(n\log n)\) 的空间,但还是过不了。
实际上,将 \(t\) 升序排序后,若 \(k\le \sqrt{n}\),那么我们用一个变量 \(p\) 删去 \(1\sim t-1\) 对答案的贡献就能直接计算出正确的结果。
时间复杂度:\(O(n\sqrt{n})\),空间复杂度 \(O(n)\)。
Code
// Problem: CF103D Time to Raid Cowavans
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF103D
// Memory Limit: 68 MB
// Time Limit: 4000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 5;
const int maxm = 550;
typedef long long ll;
int n,a[maxn],m;
struct node {
int t,k,id;
node() {
t = k = id = 0;
}
}Q[maxn];
ll s[maxm][maxm];
ll ans[maxn];
int main() {
scanf("%d",&n);
int t = sqrt(n);
for(int i = 1;i <= n;++ i) {
scanf("%d",&a[i]);
for(int j = 1;j <= t;++ j)s[j][i % j] += a[i];
}
scanf("%d",&m);
for(int i = 1;i <= m;++ i) {
scanf("%d %d",&Q[i].t,&Q[i].k);
Q[i].id = i;
}
sort(Q + 1 , Q + 1 + m , [&](const node& p,const node& q) {
return p.t < q.t;
});
int p = 1;
for(int i = 1;i <= m;++ i) {
if(Q[i].k <= t) {
for(;p < Q[i].t;++ p)
for(int j = 1;j <= t;++ j)s[j][p % j] -= a[p];
ans[Q[i].id] = s[Q[i].k][Q[i].t % Q[i].k];
}
else {
for(int j = Q[i].t;j <= n;j += Q[i].k)ans[Q[i].id] += a[j];
}
}
for(int i = 1;i <= m;++ i)printf("%lld\n",ans[i]);
return 0;
}
后面 vp 了一场 ABC,结果 E 题简单 BFS 打崩了,心态爆炸 QAQ。
[ABC246F]typewriter
\(n\) 个字符串 \(s_{1\sim n}\),每个字符串都是 \(\texttt{abcd\ldots z}\) 的子序列。
你可以选择其中一个字符串 \(s_i\),用 \(s_i\) 中的字符组成一个长为 \(L\) 的字符串。
求可以组成的字符串的数量。
\(1\le n\le 18,1\le L\le 10^9\)。
看到 \(L\) 的范围我下意识地去想矩阵快速幂优化 DP,结果搞不出来,因为重复的数量实在不好维护。
看了题解后,我恍然大悟:\(n\) 这么小的范围,有重复,联想到什么?
没错,容斥原理。
如果若干个字符串有 \(cnt\) 个重复的字符,那么它们间重复字符串的数量即为 \(cnt^L\)。
原因不难理解,想要重复,必然是 \(1\sim L\) 每个字符都是这 \(cnt\) 个字符中的某个。
想明白了这个,很容易写出代码。
时间复杂度:\(O(2^n(n+\log L))\)。
Code
// Problem: F - typewriter
// Contest: AtCoder - AtCoder Beginner Contest 246
// URL: https://atcoder.jp/contests/abc246/tasks/abc246_f
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
const int maxn = 20;
typedef long long ll;
const ll mod = 998244353;
ll m;
char s[maxn][30];
int n,sum[maxn],len[maxn];
ll power(ll x,ll y) {
ll ans = 1;
for(;y;y >>= 1) {
if(y & 1)(ans *= x) %= mod;
(x *= x) %= mod;
}
return ans;
}
int popcount(int x) {
int ans = 0;
for(;x;x -= x & -x)++ ans;
return ans;
}
int main() {
scanf("%d %lld",&n,&m);
ll ans = 0;
for(int i = 1;i <= n;++ i) {
scanf("%s",s[i] + 1);
len[i] = strlen(s[i] + 1);
for(int j = 1;j <= len[i];++ j)sum[i] |= 1 << (s[i][j] - 'a');
}
//这里我一开始很疑惑:交集不是等于全集减去补集的并集吗,为啥不用提前算全集
//后来想明白了,k 的二进制位只有一位时其实就计算上了全集的贡献
for(int k = 1;k < (1 << n);++ k) {
int popcnt = 0,cur = (1 << 26) - 1;
for(int i = 1;i <= n;++ i) {
if(!(k >> (i - 1) & 1))continue ;
++ popcnt;
cur &= sum[i];
}
(ans += ((popcnt & 1) ? 1ll : -1ll) * power(popcount(cur) , m) % mod + mod) %= mod;
}
printf("%lld",ans);
return 0;
}
标签:le,颓废,int,ll,12,maxn,2022.8,ans,sum 来源: https://www.cnblogs.com/Royaka/p/16581775.html