abc252_d Distinct Trio 题解
Posted Toppat Space Station
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了abc252_d Distinct Trio 题解相关的知识,希望对你有一定的参考价值。
这是数学题耶!
题意
给定一个整数 \\(n\\) 和一个长度为 \\(n\\) 的整数序列 \\(a\\),求满足以下要求的三元组个数:
- \\(1 \\leqslant i < j < k \\leqslant n\\)。
- \\(a_i \\ne a_j\\),\\(a_j \\ne a_k\\),\\(a_k \\ne a_i\\)。
思路
先想正着做,好,不会。
正着做不行就反着做,先算出所有情况,再去掉不合法。
- 所有情况的公式:\\(\\fracn \\times (n-1) \\times (n - 2)6\\)。
- 公式小解析:首先不考虑顺序,选掉一个数就少一个,选 \\(3\\) 个就是 \\(n \\times (n - 1) \\times (n - 2)\\)。
- 考虑顺序,去掉不合法,除以 \\(6\\)。
- 不合法的公式:
- 不合法的情况就两种:
- 两个数相同,另一个不同。
- 三个数都相同。
- 令 \\(cnt_i\\) 表示 \\(i\\) 在序列中的出现次数。
- 对于一个出现在序列中的整数 \\(i\\),它对答案的负贡献分为以下两种:
- \\(\\fraccnt_i \\times (cnt_i - 1) \\times (cnt_i - 2)6\\),三个元素都相同,与所有情况同理。
- \\(\\fraccnt_i \\times (cnt_i - 1) \\times (n - cnt_i)2\\),其中两个元素相同需要去重,除以 \\(2\\),另外一个数可以是非 \\(i\\) 的任意数。
- 不合法的情况就两种:
记得开个 long long
。
Code
#include <iostream>
using namespace std;
using ll = long long;
const int N = 2e5 + 10;
int n, a[N], cnt[N];
bool f[N];
ll ans; // 记得开 long long
int main ()
ios::sync_with_stdio(0), cin.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
cnt[a[i]]++; // 统计出现次数
ans = 1ll * n * (n - 1) * (n - 2) / 6; // 所有情况
for (int i = 1; i <= n; i++)
if (f[a[i]]) // 同一个数不用多次求
continue;
f[a[i]] = 1; // 标记
ans -= 1ll * cnt[a[i]] * (cnt[a[i]] - 1) * (cnt[a[i]] - 2) / 6; // 套用公式
ans -= 1ll * cnt[a[i]] * (cnt[a[i]] - 1) * (n - cnt[a[i]]) / 2;
cout << ans;
return 0;
ABC291题解(D-G)
ABC291
D - Flip Cards
Solution:
考虑DP,定义状态\\(F_i,0\\)为第\\(i\\)张卡片正面朝上的方案数,\\(F_i,1\\)为第\\(i\\)张卡片背面朝上的方案数,每次check是否相同然后转移即可
int f[N][2];
int a[N];
int b[N];
void solve()
int n;
cin >> n;
for (int i = 1;i <= n;i ++)
cin >> a[i] >> b[i];
f[1][0] = 1;
f[1][1] = 1;
for (int i = 2;i <= n;i ++)
f[i][0] = (f[i - 1][0] * (a[i - 1] != a[i]) + f[i - 1][1] * (b[i - 1] != a[i])) % mod;
f[i][1] = (f[i - 1][0] * (a[i - 1] != b[i]) + f[i - 1][1] * (b[i - 1] != b[i])) % mod;
cout << (f[n][0] + f[n][1]) % mod << endl;
E - Find Permutation
Solution:
考虑到题目所说的大小关系,可以联系到是一个有向图的形式,如果\\(a\\)和\\(b\\)有一条有向边,则含义为\\(a\\leqslant b\\),所以我们可以发现,其实题目只是求一个拓扑序,观察第二个样例,我们还可以发现不能同时有多个点在拓扑序的同一时刻入队,所以就构造完了。
vector<int> G[N];
queue<int> qq;
int c[N];
int d[N];
int n, m;
vector <int > ans;
int f[N];
bool topsort()
int z=0;
for (int i=1;i<=n;i++)
if (!d[i])qq.push(i),z++,ans.push_back(i);
while (!qq.empty())
if(qq.size() != 1)
return false;
int t = qq.front();
qq.pop();
for (int i : G[t])
d[i]--;
if (!d[i])
qq.push(i);
ans.push_back(i);
z++;
return z==n;
void solve()
cin >> n >> m;
map<PII,bool> mp;
for (int i = 1;i <= m;i ++)
int x,y;
cin >> x >> y;
d[y]++;
G[x].push_back(y);
if(topsort())
cout << "Yes" << endl;
int now = 1;
vector<int> last(n + 1);
for (int i : ans) last[i] = now++;
for (int i = 1;i <= n;i ++) cout << last[i] << \' \'; cout << endl;
else cout << "No" << endl;
F-Teleporter and Closed off
Solution:
观察到\\(m \\leqslant 10\\),且题目要求的是不经过一个点的时候的最短路,所以对于不经过的点,我们只需要枚举其前面最多\\(10\\)个位置,他们是需要"跨过"当前不能经过的点的,所以DP先处理出来两个最短路,一个从\\(1\\)到后面的点的,一个从后面的点到\\(n\\)的最短路,枚举完点就可以很快的算出答案了。
int f[N][2];
void solve()
int n , m;
cin >> n >> m;
vector<string> s(n + 1);
for (int i = 2;i <= n;i ++) f[i][1] = 1e18;
for (int i = 1;i <= n - 1;i ++) f[i][0] = 1e18;
for (int i = 1;i <= n;i ++)
cin >> s[i];
s[i] = " " + s[i];
for (int j = 1;j <= m && i + j <= n;j ++)
if(s[i][j] == \'1\') f[i + j][1] = min(f[i + j][1], f[i][1] + 1);
for (int i = n;i >= 1;i --)
for (int j = 1;j <= m && i + j <= n;j ++)
if(s[i][j] == \'1\')
f[i][0] = min(f[i][0],f[i + j][0] + 1);
for (int i = 2;i <= n - 1;i ++)
int ans = 1e18;
for (int j = max(1ll,i + 1 - m);j <= i - 1;j ++)
for (int k = i + 1 - j;k <= min(m , n);k ++)
if(s[j][k] == \'1\')
ans = min(ans , f[j][1] + f[j + k][0] + 1);
if(ans != 1e18)
cout << ans << \' \';
else
cout << -1 << \' \';
G - OR Sum
Solution:
暴力的复杂度是\\(O(N^2)\\),所以考虑优化。复杂度来自两个地方,一个是枚举循环的情况,\\(O(N)\\),还有是扫描一遍算或的值,\\(O(N)\\),前一个循环不好优化,因为每个数都很小,所以考虑优化后面这一个运算的复杂度。首先我们可以对每位进行分析,\\(A|B = A + B - A \\& B\\),这样子拆开式子后,我们就可以发现,前两项会是一个定值,就是所有元素的和,将\\(B\\)倒序之后,后面一项,对于每一位的情况就是\\(\\sum_i = 1^nA_i + k \\& B_n - i\\),显然是个卷积的形式,二进制最多五位,做五次卷积分别算贡献就做出来了。
void solve()
int n;
cin >> n;
int s = 0;
for (int i = 1;i <= n;i ++) cin >> A[i], s += A[i];
for (int i = 1;i <= n;i ++) cin >> B[i], s += B[i];
for (int c = 0;c < 5;c ++)
memset(f,0,sizeof(f));memset(g,0,sizeof(g));
for (int i = 0;i < n;i ++)
f[i] = f[i + n] = (A[i + 1] >> c) & 1;
g[i] = (B[n - i] >> c) & 1;
poly_mul(f,g,2 * n);
for (int i = 0;i < n;i ++)
ans[i] += f[n + i] * (1ll << c);
int now = -1;
for (int i = 0;i < n;i ++)
now = max(now , s - ans[i]);
cout << now << endl;
以上是关于abc252_d Distinct Trio 题解的主要内容,如果未能解决你的问题,请参考以下文章