Atcoder-ABC150-DEF题解

Atcoder题解汇总

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;
}
posted @ 2022-05-27 17:16  Roshin  阅读(96)  评论(0编辑  收藏  举报
-->