Codeforces Round #822 (Div. 2) EF
E. Rectangular Congruence
题意
给你一个长度为 n n n的数组 b b b,让你构造一个 n × n n\times n n×n的矩阵 a a a,使其满足 0 ≤ a i , j < n , 1 ≤ i , j , ≤ n 0\le a_{i,j}<n,1\le i,j,\le n 0≤ai,j<n,1≤i,j,≤n,且 a r 1 , c 1 + a r 2 , c 2 ≠ a r 1 , c 2 + a r 2 , c 1 ( m o d n ) , 1 ≤ c 1 < c 2 ≤ n , 1 ≤ r 1 < r 2 ≤ n a_{r1,c1}+a_{r2,c2}\neq a_{r1,c2}+a_{r2,c1} (mod\ n),1\le c_1<c_2\le n,1\le r_1<r_2\le n ar1,c1+ar2,c2=ar1,c2+ar2,c1(mod n),1≤c1<c2≤n,1≤r1<r2≤n。
思路
- 推式子
让你求 a r 1 , c 1 + a r 2 , c 2 ≠ a r 1 , c 2 + a r 2 , c 1 ( m o d n ) a_{r1,c1}+a_{r2,c2}\neq a_{r1,c2}+a_{r2,c1} (mod\ n) ar1,c1+ar2,c2=ar1,c2+ar2,c1(mod n),转换一下式子等价于求 a r 1 , c 1 − a r 1 , c 2 ≠ a r 2 , c 1 − a r 2 , c 2 ( m o d n ) a_{r1,c1}-a_{r1,c2}\neq a_{r2,c1}-a_{r2,c2} (mod\ n) ar1,c1−ar1,c2=ar2,c1−ar2,c2(mod n),等价于同行任意两个位置的差,不能在其它行这两个位置差出来, 考虑做一个由于是 m o d n \mod n modn 意义下的,因此考虑对于每一行构造一个 d d d唯一的等差数列即可,因此将第 i i i行的 d d d 构造为 i i i 直接输出就好
Code
#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[1010][1010], b[1010];
int main() {
ios::sync_with_stdio(false), cin.tie(0);
cin >> n;
for (int i = 1; i <= n; i ++) cin >> b[i];
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= n; j ++)
cout << (i * (j - i + n) + b[i]) % n << " \n"[j == n];
return 0;
}
F. Zeros and Ones
题意
给你一个长度为正无穷按照下面过程构造出的 0 / 1 0/1 0/1串 S S S,构造如下:
一开始 S = ′ 0 ′ S='0' S=′0′,令 S ′ = S ⊕ ′ 111...11 1 ′ ( 即将 S 每一位取反 ) S'=S\oplus '111...111'(即将S每一位取反) S′=S⊕′111...111′(即将S每一位取反) ,然后令 S = S + S ′ (即将 S 和 S ′ 拼接起来) S=S+S'(即将S和S'拼接起来) S=S+S′(即将S和S′拼接起来)。
给你 n , m n,m n,m ,问你 ∑ i = 0 m − 1 S i ! = S n + i \displaystyle \sum_{i=0}^{m-1}S_i!=S_{n+i} i=0∑m−1Si!=Sn+i。
思路
- d p dp dp
参考(68 封私信 / 80 条消息) Ander - 知乎 (zhihu.com)
想办法快速求出 S i S_i Si的值,由于每次相当于 × 2 \times 2 ×2 再将取反的加到后面,也就是能有多少个 2 2 2的次幂就取了多少次反,因此 S i = S_i= Si=( i i i的二进制表示中 1 1 1出现的次数) % 2 \%2 %2
设 f [ n ] [ m ] = ∑ i = 0 m − 1 [ S i ! = S n + i ] f[n][m]=\displaystyle \sum_{i=0}^{m-1}[S_i!=S_{n+i}] f[n][m]=i=0∑m−1[Si!=Sn+i],考虑是否能从一些子状态推导出,对于边界 如果 m = 0 / 1 m=0/1 m=0/1 可以直接判断,如果 m % 2 = = 1 m\%2==1 m%2==1,我们可以直接求出最后面是否一样,将其转换成 m % 2 = = 0 m\%2==0 m%2==0的形式,因此对于 m % 2 = = 0 m\%2==0 m%2==0做如下讨论:
-
n
%
2
=
=
0
n\%2 ==0
n%2==0
- 将奇偶分开有 S 2 k ! = S n + 2 k ⇔ S 2 k + 1 ! = S n + 2 k + 1 S_{2k}!=S_{n+2k}\Leftrightarrow S_{2k+1}!=S_{n+2k+1} S2k!=Sn+2k⇔S2k+1!=Sn+2k+1(因为 2 k 2k 2k是偶数 n n n也是偶数,所以 2 k 2k 2k和 2 k + 1 2k+1 2k+1只有 2 2 2进制最后一位不同,因此 S 2 k + 1 = S 2 k + 1 S_{2k+1}=S_{2k}+1 S2k+1=S2k+1,所以上式成立)
- f [ n ] [ m ] = ∑ i = 0 m − 1 [ S i ! = S n + i ] f[n][m]=\displaystyle \sum_{i=0}^{m-1}[S_i!=S_{n+i}] f[n][m]=i=0∑m−1[Si!=Sn+i]
- f [ n ] [ m ] = 2 × ∑ k = 0 m / 2 − 1 [ S 2 k ! = S n + 2 k ] f[n][m]=\displaystyle 2\times \sum_{k=0}^{m/2-1}[S_{2k}!=S_{n+2k}] f[n][m]=2×k=0∑m/2−1[S2k!=Sn+2k]
- f [ n ] [ m ] = 2 × ∑ k = 0 m / 2 − 1 [ S 2 k ! = S n + 2 k ] f[n][m]=\displaystyle 2\times \sum_{k=0}^{m/2-1}[S_{2k}!=S_{n+2k}] f[n][m]=2×k=0∑m/2−1[S2k!=Sn+2k] (考虑式子的意义,由于下标都是偶数,因此下标右移一位, S S S的值不会变)
- f [ n ] [ m ] = 2 × ∑ k = 0 m / 2 − 1 [ S k ! = S n / 2 + k ] f[n][m]=\displaystyle 2\times \sum_{k=0}^{m/2-1}[S_{k}!=S_{n/2+k}] f[n][m]=2×k=0∑m/2−1[Sk!=Sn/2+k]
- f [ n ] [ m ] = 2 × f [ n / 2 ] [ m / 2 ] f[n][m]=\displaystyle 2\times f[n/2][m/2] f[n][m]=2×f[n/2][m/2]
-
n
%
2
=
=
1
n\%2==1
n%2==1
- 和上面偶数的一样考虑性质 S 2 k ! = S n + 2 k ⇔ S 2 k = S n + 2 k − 1 S_{2k}!=S_{n+2k}\Leftrightarrow S_{2k}=S_{n+2k-1} S2k!=Sn+2k⇔S2k=Sn+2k−1( n n n是奇数最后一位是 1 1 1,因此去掉最后一位的贡献就相等了), S 2 k + 1 ! = S n + 2 k + 1 ⇔ S 2 k = S n + 2 k + 1 S_{2k+1}!=S_{n+2k+1}\Leftrightarrow S_{2k}=S_{n+2k+1} S2k+1!=Sn+2k+1⇔S2k=Sn+2k+1
- f [ n ] [ m ] = ∑ i = 0 m − 1 [ S i ! = S n + i ] f[n][m]=\displaystyle \sum_{i=0}^{m-1}[S_i!=S_{n+i}] f[n][m]=i=0∑m−1[Si!=Sn+i]
- f [ n ] [ m ] = ∑ k = 0 m / 2 − 1 [ S 2 k ! = S n + 2 k ] + [ S 2 k + 1 ! = S n + 2 k + 1 ] f[n][m]=\displaystyle \sum_{k=0}^{m/2-1}[S_{2k}!=S_{n+2k}]+[S_{2k+1}!=S_{n+2k+1}] f[n][m]=k=0∑m/2−1[S2k!=Sn+2k]+[S2k+1!=Sn+2k+1]
- f [ n ] [ m ] = ∑ k = 0 m / 2 − 1 [ S 2 k = = S n + 2 k − 1 ] + [ S 2 k = = S n + 2 k + 1 ] f[n][m]=\displaystyle \sum_{k=0}^{m/2-1}[S_{2k}==S_{n+2k-1}]+[S_{2k}==S_{n+2k+1}] f[n][m]=k=0∑m/2−1[S2k==Sn+2k−1]+[S2k==Sn+2k+1](考虑式子的意义,右移不变)
- f [ n ] [ m ] = ∑ k = 0 m / 2 − 1 [ S k = = S ( n − 1 ) / 2 + k ] + [ S k = = S ( n + 1 ) / 2 + k ] f[n][m]=\displaystyle \sum_{k=0}^{m/2-1}[S_{k}==S_{(n-1)/2+k}]+[S_{k}==S_{(n+1)/2+k}] f[n][m]=k=0∑m/2−1[Sk==S(n−1)/2+k]+[Sk==S(n+1)/2+k] (容斥一下)
- f [ n ] [ m ] = m − ∑ k = 0 m / 2 − 1 [ S k ! = S ( n − 1 ) / 2 + k ] + [ S k ! = S ( n + 1 ) / 2 + k ] f[n][m]=\displaystyle m-\sum_{k=0}^{m/2-1}[S_{k}!=S_{(n-1)/2+k}]+[S_{k}!=S_{(n+1)/2+k}] f[n][m]=m−k=0∑m/2−1[Sk!=S(n−1)/2+k]+[Sk!=S(n+1)/2+k]
- f [ n ] [ m ] = m − f [ ( n − 1 ) / 2 ] [ m / 2 ] − f [ ( n + 1 ) / 2 ] [ m / 2 ] f[n][m]=\displaystyle m-f[(n-1)/2][m/2]-f[(n+1)/2][m/2] f[n][m]=m−f[(n−1)/2][m/2]−f[(n+1)/2][m/2]
对于每个 f [ n ] [ m ] f[n][m] f[n][m] 用它的子状态求出,记忆化一下即可,即复杂度为 O ( l o g n l o g m ) O(lognlogm) O(lognlogm)
Code
#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
LL n, m, k;
int a[N];
map<pair<LL, LL>, LL> f;
int g(LL x) {
int t = 0;
for (int i = 0; i < 64; i ++)
if (x >> i & 1) t ^= 1;
return t;
}
LL dfs(LL n, LL m) {
if (!m) return 0;
if (m == 1) return g(n);
if (f.find({n, m}) != f.end()) return f[{n, m}];
if (m & 1) return f[{n, m}] = dfs(n, m - 1) + (g(m - 1) != g(n + m - 1));
if (n % 2 == 0) return f[{n, m}] = 2ll * dfs(n / 2, m / 2);
return f[{n, m}] = m - dfs((n - 1) / 2, m / 2) - dfs((n + 1)/ 2, m / 2);
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
while (T -- ) {
cin >> n >> m;
cout << dfs(n, m) << '\n';
}
return 0;
}