Atcoder-ABC150-DEF题解
ABC 150
train#1
D. Semi Common Multiple (LCM, 数学推导)
题意
给一个长度为 \(n(1\leq n \leq 10^5)\) 数组且 \(a_i\) 是偶数, 求 \([1,M]\) 有多少个 \(X\) 满足对任意 \(X = a_i *(p + 0.5)\)
数据范围
\(1\leq M\leq 10^9\)
思路
- X 肯定是 \(a_i\) 的公倍数, 转换一下式子
- \(X = \frac{a_i}{2} * (2*p + 1)\), 即 X 一定是 \(\frac{a_i}{2}\) 的奇数倍, 那么只需要 check 一下就好了, 当然 \(X \leq M\)
Solution
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> PII;
typedef std::pair<ll, ll> PLL;
typedef double db;
#define arr(x) (x).begin(),(x).end()
#define x first
#define y second
#define pb push_back
#define mkp make_pair
#define endl "\n"
using namespace std;
const ll INF = 2e18;
ll gcd(ll a, ll b){
return b ? gcd(b, a % b) : a;
}
int main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
ll n, m;
cin >> n >> m;
vector<ll> a(n);
ll LCM = 1;
bool fl = false;
for(int i = 0;i < n; i++){
cin >> a[i];
a[i] /= 2;
if(LCM == INF)
continue;
LCM = LCM / gcd(a[i], LCM) * a[i];
if(LCM > m)
LCM = INF;
}
if(LCM == INF){
cout << 0 << endl;
return 0;
}
for(int i = 0; i < n; i++){
if((LCM / a[i]) % 2 == 0)
fl = true;
}
if(LCM == INF || fl)
cout << 0 << endl;
else
cout << 1ll * (m / LCM + 1) / 2 << endl;
return 0;
}
E. Change a Little Bit (组合计数推导)
题意
给定长度为 \(n\) 的两个01串 \(S,T\), 定义 \(f(S,T)\) 为以下操作最小花费总和:
改变 \(S[i]\) , 此次花费定义为操作之前 \(S\) 和 \(T\) 不同下标数 \(D*C_i\)
数据范围
\(1\leq N\leq 2 * 10^5\)
\(1\leq C_i\leq 10^9\)
思路
- 考虑按贡献来计算, 按照每一个 \(C_i\) 的贡献来计算, 显然贪心地想, 大的 \(C_i\) 要后选, 小的先选
- 那么假设 \(C_i\) 已从大到小排序, \(1\leq i\leq n\), 当 \(i\) 不同时, 那么设不包括 \(i\) 下标有 \(j\) 个数不同, 则 \(j\leq i\) , 否则贪心不成立
- 那么枚举一下 \(j\) 的大小, \(j=0\) 时, 前面全是相同的数, 其余的数(除开 \(i\)) 总共有 \(n-i\) 个随便什么情况(因为按贡献考虑互相独立), 所以此次贡献为 \(2^{n-i}*C[i]\)
- 更一般的来看, 对于每个 \(j\), 贡献为 \(2^{n-i}*C_i^j * (j + 1) * C[i]\), 则对于每个 \(C[i]\) 其贡献为 \(2^{n-i}*C[i] * \Sigma_{j=0}^{i-1} C_{i-1}^j * (j+1)\)
- 再转化一下, 利用公式 \(C_n^i*i = n*2^{n-1}\), \(原式=2^{n-i}*C[i]*((i-1)*2^{i-2} + 2^{i-1}\) , 代码中 \(i\) 从 0 开始.
- 最后一定不要漏掉, 关于每个位置的相同与不同定义是可以变化的 \(01,10\), \(00,11\) 分别属于不同与相同位与位之间可以任意组合 , 所以最后答案还要乘上 \(2^n\)
Solution
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> PII;
typedef std::pair<ll, ll> PLL;
typedef double db;
#define arr(x) (x).begin(),(x).end()
#define x first
#define y second
#define pb push_back
#define mkp make_pair
#define endl "\n"
using namespace std;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
ll mi[N];
// n * 2 ^n-1
int main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n;
vector<ll> c(n);
mi[0] = 1;
for(int i = 1; i <= n; i++)
mi[i] = mi[i - 1] * 2ll % mod;
for(int i = 0; i < n; i++)
cin >> c[i];
sort(arr(c));
reverse(arr(c));
ll ans = 0;
for(int i = 0; i < n; i++){
int x = i + 1;
ans = (ans + mi[n - x] % mod * c[i] % mod * (i * mi[max(i - 1, 0)] % mod + mi[i])) % mod;
}
cout << mi[n] * ans % mod << endl;
return 0;
}
F. Xor Shift (XOR差分性 + KMP)
题意
给了长度为 \(n\) 的两个序列 \(a,b\), 找出所有的 \((k,x)\) 满足 \(b_i=a_{i+k\mod N} XOR x\)
数据范围
\(1\leq n \leq 2*10^5\)
\(0\leq a_i \leq 2^30\)
思路
b[i]=a[i+k]^X -> b[i]^a[i+k] = X = b[i+1]^a[i+k+1] -> b[i] ^ b[i + 1] = a[i+k] ^ a[i+k+1]
- 转化后对 \(a,b\) 作差分, 答案转化为 \(b\) 在 \(a\) 中的出现次数, 就是有多少个 \(k\), 对于每个 \(k\) 的 \(x\) 很好求
- 显然将 \(b\) 作为模板串需要将 \(a\) 拉成环再破成链
- 最后做一次 KMP 就可以求解
Solution
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> PII;
typedef std::pair<ll, ll> PLL;
typedef double db;
#define arr(x) (x).begin(),(x).end()
#define x first
#define y second
#define pb push_back
#define mkp make_pair
#define endl "\n"
using namespace std;
const int N = 2e5 + 10;
int ne[2 * N], n, ans = 0;
void get_ne(vector<int>& s){
int len = 2 * n;
ne[1] = 0;
for(int i = 2, j = 0; i <= len; i++){
while(j && s[j + 1] != s[i]) j = ne[j];
if(s[i] == s[j + 1]) j++;
ne[i] = j;
}
}
vector<int> Match(vector<int>& s, vector<int>& p){
int lens = 2 * n - 1, lenp = n;
vector<int> res;
for(int i = 1, j = 0; i <= lens; i++){
while(j && s[i] != p[j + 1]) j = ne[j];
if(s[i] == p[j + 1]) j++;
if(j == lenp){
res.pb(i - n);
ans++;
j = ne[j];
}
}
return res;
}
int main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
vector<int> a(2 * n + 1, 0), xa(n + 1, 0);
vector<int> b(n + 1, 0), xb(n + 1, 0);
for(int i = 1; i <= n; i++)
cin >> xa[i];
for(int i = 1; i <= n; i++)
cin >> xb[i];
for(int i = 1; i <= n; i++){
if(i != n){
a[i] = xa[i] ^xa[i + 1];
b[i] = xb[i] ^ xb[i + 1];
}
else{
a[i] = xa[i] ^ xa[1];
b[i] = xb[i] ^ xb[1];
}
a[i + n] = a[i];
}
get_ne(a);
auto res = Match(a, b);
for(auto k: res){
cout << k << " " << (xb[1] ^ xa[1 + k]) << endl;
}
return 0;
}