AtCoder Regular Contest 070&071
ARC070 只会个 D QAQ,所以就合并到 ARC071 了。
ARC070D - No Need
给定 \(n\) 个整数 \(a_1\sim a_n\),对于 \(a_i\),若原来所有包含 \(a_i\) 且和 \(\ge K\) 的子集去掉 \(a_i\) 后和仍然 \(\ge K\),则称 \(a_i\) 是「不重要」的。求「不重要」的 \(a_i\) 数量。
\(1\le n,K\le 5\times 10^3,1\le a_i\le 10^9\)
大水题。
首先,若 \(a_i\ge K\),则 \(a_i\) 一定是「重要」的,因为 \(\{a_i\}\) 这个集合去掉 \(a_i\) 后就不满足条件。
将 \(\lt K\) 的 \(a_i\) 提取出来,发现问题就等价于:对于 \(a_i\),是否存在一种方案,使得 \(a_{1\sim i-1},a_{i+1\sim n}\) 的某个子集和值域在 \([k-a_i,k-1]\) 间。
直接背包是 \(\mathcal O(n^2K)\) 的,std::bitset
优化一下能达到 \(\mathcal O(\frac{n^2K}{\omega})\)。
但是这其实是一个经典的问题,模板在 [luogu P4141]消失之物,直接分治可以做到 \(\mathcal O(nk\log n)\),用 std::bitset
优化到 \(\mathcal O(\frac{nk\log n}{\omega})\)。
Code
// Problem: D - No Need
// Contest: AtCoder - AtCoder Regular Contest 070
// URL: https://atcoder.jp/contests/arc070/tasks/arc070_b
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
const int maxn = 5005;
std::bitset<maxn> f;
int n,k,a[maxn],ans;
void solve(int l,int r) {
if(l > r)return ;
if(l == r) {
for(int i = k - 1;i >= k - a[l]&&i >= 1;-- i)
if(f[i])return ;
++ ans;
return ;
}
std::bitset<maxn> tmp = f;
int mid = l + r >> 1;
for(int i = l;i <= mid;++ i)
f |= f << a[i];
solve(mid + 1 , r);
f = tmp;
for(int i = mid + 1;i <= r;++ i)
f |= f << a[i];
solve(l , mid);
return ;
}
int main() {
scanf("%d %d",&n,&k);
for(int i = 1;i <= n;++ i)
scanf("%d",&a[i]);
std::sort(a + 1 , a + 1 + n);
n = std::lower_bound(a + 1 , a + 1 + n , k) - a - 1;
f.set(0 , true);
solve(1 , n);
printf("%d\n",ans);
return 0;
}
ARC071E - TrBBnsformBBtion
给定两字符串 \(s,t\),你可以进行三种操作:
\(\tt{A}\to BB\)
\(\tt B\to AA\)
删除 \(\tt AAA\) 或 \(\tt BBB\)
\(Q\) 次询问,每次给定 \(a,b,c,d\),询问 \(s_{a\sim b}\) 是否可以经过若干次操作变为 \(t_{c\sim d}\)
\(1\le |s|,|t|,Q\le 10^5\)
首先要发现,\(\tt A\to BB\to AAAA\to A\),也就是说操作是可逆的。
并且 \(\tt AB\to BBAA\to BBBBA\to BA\),即可以任意交换左右两字母。
综上,我们只需要让 \(s_{a\sim b},t_{c\sim d}\) 都变为 \(\tt A\),查询其差值是否 \(\equiv 0 \pmod{3}\) 即可。
时间复杂度 \(\mathcal O(|s|+|t|+Q)\)
Code
口胡的,没写,洛谷有相同思路的代码实现。
ARC071F - Infinite Sequence
定义 \(n-\)可爱序列 指无限长的由 \(\{1,2...,n\}\) 组成的序列。同时 \(a_1,a_2...\)满足以下条件:
第 \(n\) 个及以后的元素是相同的,即若 \(\forall i,j\geq n,a_i=a_j\)
对于每个位置 \(i\),紧随第 \(i\) 个元素后的 \(a_i\) 个元素是相同的,即若 \(\forall i<j<k\le i+a_i,a_j=a_k\)
输入 \(n\),请输出 \(n-\)可爱序列的数量 \(\bmod\ 10^9+7\)
\(n\leq{10^6}\)。
翻译 by @皎月半洒花
萌萌计数 DP。
首先发现,若 \(\exist i\in [1,n),a_i\gt 1\land a_{i+1}\gt 1\),则 \(\forall j\in [i+1,n],a_j=a_i\)
那么,设 \(f(i)\) 表示前 \(i\) 个数中 \(a_i\gt 1\) 的方案数(注意:\(a_i\) 具体是什么先不考虑,最后计算答案的时候再考虑)。
则 \(f(i)=\sum\limits_{j=3}^{i-1} f(i-j)\times (j-1) + 1\)
因为这题肯定要 \(\mathcal O(n)\) 的复杂度,考虑把刷表换成填表。
我的方法是二阶前缀和,即令 \(s(i)=\sum\limits_{j=1}^i f(j),sum(i)=\sum\limits_{j=1}^{i} s(j)\),则 \(f(i)=sum(i-3)+1\),直接维护即可。
最后考虑计算答案。
首先是全为 1 的情况,贡献为 1。
然后是 \(a_{1\sim n-1}\) 有一个 \(\gt 1\),后面全相等的情况,贡献为 \(s(n-1)\times n\times (n-1)\)。
这个式子解释一下:因为我们上面没有考虑 \(a_i\) 具体是几,所以这里要乘 \((n-1)\),并且后面全相等的数有 \(n\) 种,故贡献为 \(s(n-1)\times n\times (n-1)\)。
最后考虑 \(a_n\gt 1\) 的情况,因为 \(\forall i\in (n,+\infty),a_i=a_n\),故这种情况的贡献只有 \(f(n)\times (n-1)\)
把贡献累加即可。时间复杂度 \(\mathcal O(n)\)。
Code
// Problem: F - Infinite Sequence
// Contest: AtCoder - AtCoder Regular Contest 071
// URL: https://atcoder.jp/contests/arc071/tasks/arc071_d
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using i64 = long long;
const int maxn = 1e6 + 5;
const i64 mod = 1e9 + 7;
int n;
i64 f[maxn],s[maxn],sum[maxn];
int main() {
scanf("%d",&n);
for(int i = 1;i <= n;++ i) {
f[i] = (sum[std::max(0 , i - 3)] + 1) % mod;
s[i] = (s[i - 1] + f[i]) % mod;
sum[i] = (sum[i - 1] + s[i]) % mod;
}
printf("%lld\n",(1ll * s[n - 1] * n % mod * (n - 1) % mod + 1ll * f[n] * (n - 1) % mod + 1) % mod);
return 0;
}
NOIp 2022 马上开始了,慌得一批.jpg