cf 1829H
题目大意:给定一个长度为n的数组a(0<=a[i]<=63, 1<=n<=2e5),整数k(0<=k<=6),
求a有多少个子序列的按位与(and)值的二进制中有k个1。
分析:a[i]<=63,说明任意子序列的and值也<=63,这样我们可以求出and值为0-63的所有子序列
数量,最后判断0-63有哪些的二进制里只有k个1的,把答案累加即可。
dp[i][j]表示前i个元素中and值为j的数量,转移方程很简单。
void solve() {
int n, k;
cin >> n >> k;
vector<vector<int> > dp(n + 1, vector<int>(1 << 6));
for (int i = 1; i <= n; i++) {
int a;
cin >> a;
for (int mask = 0; mask < (1 << 6); mask++) {
dp[i][mask] = (dp[i - 1][mask] + dp[i][mask]) % mod;
dp[i][mask & a] = (dp[i - 1][mask] + dp[i][mask & a]) % mod;
}
dp[i][a] = (dp[i][a] + 1) % mod; //本身为1个新序列
}
ll ans = 0;
for (int mask = 0; mask < (1 << 6); mask++) {
if(__builtin_popcount(mask) == k) {
ans = (ans + dp[n][mask]) % mod;
}
}
cout << ans << "\n";
}
cf 1792D
题目大意:给你n个长度为m的排列(n<=4e5, 1<=m<=10),假设长度为 p1,p2,…,pm 的排列的美度
是 k 中最大的 p1=1,p2=2,…,pk=k。如果是p1≠1,那么美度就是0。
两个排列p⋅q的乘积是排列r,使得r[j]=q[p[j]]。
对于从1到n的每个i,打印从1到n的所有j的排列组合ai⋅aj的最大美度。(可能是i==j)。
假设p*q组成的r的美度为k,是不是可以得到p*q=(1,2...k,r[k+1]...)。
移项:p=(1,2...k,r[k+1]...)*q^(-1)。
可以看出q^(-1)和p的前k个数字相同,所以我们只需要找到p与其他所有排列的逆排列的最大公共前缀长度即可。
做法:先存好每一个排列的逆排列,排序后用lower_bound查找即可,最大公共前缀长度不是找到的,就是它的前一个。
int getres(vector<int> a, vector<int> b) {
int res = 0;
while(res < (int)a.size() && a[res] == b[res]) {
res++;
}
return res;
}
void solve() {
int n, m;
cin >> n >> m;
vector<vector<int> > a(n, vector<int>(m)), b = a;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> a[i][j];
--a[i][j];
b[i][a[i][j]] = j;
}
}
sort(b.begin(), b.end());
for (int i = 0; i < n; i++) {
int j = lower_bound(b.begin(), b.end(), a[i]) - b.begin();
int ans = 0;
if(j > 0) ans = max(ans, getres(a[i], b[j - 1]));
if(j < n) ans = max(ans, getres(a[i], b[j]));
cout << ans << ' ';
}
cout << "\n";
}
cf 1770C
题目大意:有一个长度为n的数组a (n的总和不超过1000,1<=a[i]<=1e18),
问你是否存在一个正整数x,使得所有(1<=i, j<=n)都满足gcd(a[i] + x, a[j] + x) == 1。
对于给定的x,让我们记b[i]=a[i]+x。
条件「对于gcd(b[i],b[j])==1(1<=i,j<=n)恒成立」等价于「每个质数p只能整除至多一个b[i]」。
那么,对于一个质数p,我们能否判断p,是否总是整除至少两个b[i](无论x的取值)。
根据鸽巢原理,我们只需要枚举小于等于n/2的质数(枚举了合数也不会错)。
cnt[i]为i在(a[1]%p...a[n]%p)中出现的个数,当cnt中的最小值大于等于2时,我们就输出NO,
若对于所有质数都成立,则我们可以列出一个同余方程组,并使用中国剩余定理求解合适的x。
void solve() {
int n;
cin >> n;
vector<ll> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
sort(a.begin(), a.end());
for (int i = 0; i < n - 1; i++) {
if(a[i] == a[i + 1]) {
cout << "NO\n";
return;
}
}
for (int mod = 2; mod <= n / 2; mod++) {
vector<int> cnt(mod);
for (int i = 0; i < n; i++) {
cnt[a[i] % mod]++;
}
if(*min_element(cnt.begin(), cnt.end()) >= 2) {
cout << "NO\n";
return;
}
}
cout << "YES\n";
}