其他分享
首页 > 其他分享> > 2022.8.12 颓废记录

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