A. A Bit Common
如果一个子序列的 A N D AND AND值为 1 1 1,则这个子序列中的数的二进制最低位全为 1 1 1,除去二进制最低位的其他 m − 1 m-1 m−1位至少有一个 0 0 0,那我们就把数分成二进制最低位为 1 1 1和最低位为 0 0 0来考虑,计算所有二进制最低位为 1 1 1的数 A N D AND AND值为 1 1 1的情况。
记二进制最低位为 1 1 1的数有 k k k个,由于不同顺序的序列对答案的贡献是不一样的,如 { 1 , 2 , 3 } \{1,2,3\} {1,2,3}和 { 1 , 3 , 2 } \{1,3,2\} {1,3,2}算作两个不同的序列,所以我们要计算这 k k k个数出现在什么位置,情况有 ( n k ) \left(\begin{array}{c}n \\ k\end{array}\right) (nk)种,如果剩余 m − 1 m-1 m−1位随意取值的话,情况有 2 k ( m − 1 ) 2^{k(m - 1)} 2k(m−1)种,但是前文提到这 m − 1 m-1 m−1位上每位至少存在一个 0 0 0,所以对于每一位都要去除掉全为 1 1 1的情况,所以情况只有 ( 2 k − 1 ) m − 1 (2^k-1)^{m-1} (2k−1)m−1种情况。
二进制最低位为 0 0 0的数只剩 n − k n-k n−k个了,除去二进制的最低位还剩 m − 1 m-1 m−1位,因为 A N D = 1 AND=1 AND=1的情况已经在二进制最低位为 1 1 1的数中出现了,所以这些位可以随意取值,共有 2 ( n − k ) ( m − 1 ) 2^{(n-k)(m-1)} 2(n−k)(m−1)种情况。
所以最后的答案是 ∑ k = 1 n ( n k ) ( 2 k − 1 ) m − 1 2 ( n − k ) ( m − 1 ) \sum_{k=1}^{n}\left(\begin{array}{c}n \\ k\end{array}\right)(2^k-1)^{m-1}2^{(n-k)(m-1)} ∑k=1n(nk)(2k−1)m−12(n−k)(m−1),时间复杂度 O ( n 2 ) O(n^2) O(n2)。
还有个小细节,因为模数 q q q可以取到 1 1 1且数据范围较小,所以组合数使用递推式。
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef vector<int> vi;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e18 + 100;
//const int mod = 1e9 + 7;
int C[5005][5005];
int n, m, mod;
inline ll binpow(ll a, ll b)
{
ll res = 1;
while (b)
{
if (b & 1)
res = res * a % mod;
a = (ll)a * a % mod;
b >>= 1;
}
return res;
}
void solve()
{
cin >> n >> m >> mod;
for(int i = 0;i <= n;i++)
{
C[i][0] = C[i][i] = 1;
for(int j = 1;j <= i - 1;j++) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
}
int ans = 0;
for(int k = 1;k <= n;k++)
{
int t1 = C[n][k] * binpow(binpow(2, k) - 1, m - 1) % mod;
int t2 = binpow(2, (n - k) * (m - 1));
ans = (ans + t1 * t2 % mod) % mod;
}
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
//cin >> t;
while (t--)
solve();
return 0;
}
B. A Bit More Common
和 A A A题不一样的是,这题需要序列中至少有两个子序列满足 A N D = 1 AND=1 AND=1,正难则反,我们来计算序列中只有一个子序列满足 A N D = 1 AND=1 AND=1的情况,用上一题算出来的结果减去这种情况的数量即为所求。
因为只有一个子序列满足 A N D = 1 AND=1 AND=1,所以当该子序列中去掉一个元素后剩下的数 A N D ≠ 1 AND\neq1 AND=1。
同样的,满足 A N D = 1 AND=1 AND=1的子序列除去二进制的最低位,剩余的 m − 1 m-1 m−1列至少有一个 0 0 0,我们只关心那些只有一个 0 0 0的列,把这些列称为关键列,一个关键列可以对某一行做出贡献。
所以只要满足每一行都被关键列覆盖就满足条件,枚举关键列的数量 t t t和行数 k k k,行数即为选择的二进制最低位为 1 1 1的数的数量。令 f [ k ] [ t ] f[k][t] f[k][t]为 t t t个关键列覆盖 k k k行的方案数。因为可能出现一个行被多个关键列覆盖的情况,所以移除某个关键列后被覆盖的行数可能为 k k k或者 k − 1 k-1 k−1,那我们就可以写出转移方程: f [ k ] [ t ] = k ∗ ( f [ k ] [ t − 1 ] + f [ k − 1 ] [ t − 1 ] ) f[k][t]=k*(f[k][t-1]+f[k-1][t-1]) f[k][t]=k∗(f[k][t−1]+f[k−1][t−1])除去关键列,还剩下 m − 1 − t m-1-t m−1−t列,这些列不能被选为关键列且要减去全为 1 1 1的情况,所以每一列都有 2 k − k − 1 2^k-k-1 2k−k−1种方案可选。由于 k = 1 k=1 k=1时所有情况都不行,
所以最后的总数为 ∑ k = 2 n ( n k ) 2 ( n − k ) ( m − 1 ) ( m − 1 t ) ( 2 k − k − 1 ) m − 1 − t \sum_{k=2}^{n}\left(\begin{array}{c}n \\ k\end{array}\right)2^{(n-k)(m-1)}\left(\begin{array}{c}m-1 \\ t\end{array}\right)(2^k-k-1)^{m-1-t} ∑k=2n(nk)2(n−k)(m−1)(m−1t)(2k−k−1)m−1−t,用上一题的答案减去这个式子的值即为所求。
值得注意的是,这题需要预处理一些数据,不然 O ( n 2 l o g n ) O(n^2logn) O(n2logn)的时间复杂度会超时。
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef __uint128_t ulll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e18 + 100;
//const int mod = 1e9 + 7;
int n, m, mod;
int f[5005][5005], C[5005][5005], pre[25000005], pre2[5005];
inline ll binpow(ll a, ll b)
{
ll res = 1;
while (b)
{
if (b & 1)
res = res * a % mod;
a = (ll)a * a % mod;
b >>= 1;
}
return res;
}
void solve()
{
int ans1 = 0, ans2 = 0;
cin >> n >> m >> mod;
pre[0] = 1;
for(int i = 1;i <= n * m;i++) pre[i] = pre[i - 1] * 2 % mod;
for(int i = 0;i <= max(n, m);i++)
{
C[i][0] = C[i][i] = 1;
for(int j = 1;j <= i - 1;j++) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
}
f[0][0] = 1;
for(int k = 1;k <= n;k++)
{
for(int t = k;t <= m - 1;t++) f[k][t] = k * (f[k][t - 1] + f[k - 1][t - 1]) % mod;
}
for(int i = 2;i <= n;i++)
{
ans1 = (ans1 + C[n][i] * pre[(n - i) * (m - 1)] % mod * binpow(pre[i] - 1, m - 1)) % mod;
}
for(int k = 2;k <= n;k++) // 最低为为1的数
{
int base = pre[k] - k - 1;
int now = 1;
for(int t = m - 1;t >= k;t--) // 关键列数
{
int t1 = C[n][k] * pre[(n - k) * (m - 1)] % mod;
int t2 = C[m - 1][t] % mod * f[k][t] % mod * now % mod;
ans2 = (ans2 + t1 * t2) % mod;
now = now * base % mod;
}
}
cout << (ans1 - ans2 + mod) % mod << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
//cin >> t;
while (t--)
solve();
return 0;
}
C. Sum of Suffix Sums
维护 a [ i ] ∗ i a[i]*i a[i]∗i的前缀和,每次询问直接输出当前坐标的答案,时间复杂度 O ( q ) O(q) O(q)。
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef __uint128_t ulll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e18 + 100;
const int mod = 1e9 + 7;
int a[N];
void solve()
{
int q, now = 0;
cin >> q;
while(q--)
{
int t, v;
cin >> t >> v;
now -= t;
now++;
a[now] = now * v % mod;
a[now] = (a[now] + a[now - 1]) % mod;
cout << a[now] << '\n';
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
//cin >> t;
while (t--)
solve();
return 0;
}
H. World Finals
l z r 010506 lzr010506 lzr010506参加第一场,其他队伍都参加第二场或者 l z r 010506 lzr010506 lzr010506参加第二场,其他队伍都参加第一场,两个名次取高,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)。
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef __uint128_t ulll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e18 + 100;
const int mod = 1e9 + 7;
struct sj
{
string a;
int b, c;
} x[N], y[N];
bool cmp(sj x, sj y)
{
if(x.b == y.b) return x.c < y.c;
else return x.b > y.b;
}
void solve()
{
map<string, int> mp1, mp2;
int n, m;
cin >> n;
for(int i = 1;i <= n;i++)
{
cin >> x[i].a >> x[i].b >> x[i].c;
mp1[x[i].a] = 1;
}
cin >> m;
for(int i = 1;i <= m;i++)
{
cin >> y[i].a >> y[i].b >> y[i].c;
mp2[y[i].a] = 1;
}
sort(x+1,x+n+1,cmp);
sort(y+1,y+m+1,cmp);
int t1 = 1, t2 = 1;
for(int i = 1;i <= n;i++)
{
if(x[i].a == "lzr010506") break;
t1++;
if(mp2.count(x[i].a)) t1--;
}
for(int i = 1;i <= m;i++)
{
if(y[i].a == "lzr010506") break;
t2++;
if(mp1.count(y[i].a)) t2--;
}
cout << min(t1, t2) << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
//cin >> t;
while (t--)
solve();
return 0;
}
I. Mirror Maze
由于光的可逆性,所以在图中光路不会相交,所以图中的光路可以看作若干个链和若干个环。如果是链,那么经过反射一定会从某个镜子射出。根据光的可逆性,我们从外面射入光线,那么这束光一定会射出,通过记录并处经过的点和方向我们可以得到所有链的情况。环则同理,遍历每个镜子,如果没有射出则是环,预处理后每次询问直接输出答案,时间复杂度 O ( n m ) O(nm) O(nm)。
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef __uint128_t ulll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const double eps = 1e-9;
const int N = 1e3 + 10;
const int INF = 1e18 + 100;
const int mod = 1e9 + 7;
char boa[N][N];
int vis[N][N], vis2[N][N][4], dp[N][N][4];//dp[x][y][d] 代表(x, y)的坐标点向d传播
int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
int os, n, m;
void dfs(int x, int y, int d, int cur)
{
x += dir[d][0];
y += dir[d][1];
if(x < 1 || x > n || y < 1 || y > m) return;
dp[x][y][d ^ 2] = cur;
int add = 0;
if(boa[x][y] == '-')
if(d == 1 || d == 3)
d = 4 - d, add = 1;
if(boa[x][y] == '|')
if(d == 0 || d == 2)
d = 2 - d, add = 1;
if(boa[x][y] == '/')
d = 3 - d, add = 1;
if(boa[x][y] == '\\')
{
if(d == 2 || d == 3) d = 5 - d;
else d = 1 - d;
add = 1;
}
if(vis[x][y] == os) add = 0;
if(add) vis[x][y] = os;
dfs(x, y, d, cur + add);
}
struct node
{
int x, y, d;
};
vector<node>po;
vector<pii>pi;
void dfs2(int x, int y, int d)
{
x += dir[d][0];
y += dir[d][1];
if(x < 1 || x > n || y < 1 || y > m) return;
int add = 0;
if(boa[x][y] == '-')
if(d == 1 || d == 3)
d = 4 - d, add = 1;
if(boa[x][y] == '|')
if(d == 0 || d == 2)
d = 2 - d, add = 1;
if(boa[x][y] == '/')
d = 3 - d, add = 1;
if(boa[x][y] == '\\')
{
if(d == 2 || d == 3) d = 5 - d;
else d = 1 - d;
add = 1;
}
if(vis2[x][y][d] == os) return;
vis2[x][y][d] = os;
po.push_back({x, y, d});
if(add)
pi.push_back({x, y});
dfs2(x, y, d);
}
void solve()
{
cin >> n >> m;
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++)
cin >> boa[i][j];
for(int i = 1;i <= n;i++)
{
os++; dfs(i, 0, 0, 0);
os++; dfs(i, m + 1, 2, 0);
}
for(int i = 1;i <= m;i++)
{
os++; dfs(0, i, 1, 0);
os++; dfs(n + 1, i, 3, 0);
}
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= m;j++)
{
for(int k = 0;k < 4;k++)
{
if(dp[i][j][k]) continue;
os++;
dfs2(i, j, k);
sort(pi.begin(), pi.end());
pi.erase(unique(pi.begin(), pi.end()),pi.end());
//cout << "i: " << i << " " << "j: " << j << " " << "k: " << k << endl;
for(auto it : po)
{
dp[it.x][it.y][it.d] = pi.size();
//cout << it.x << " " << it.y << " " << it.d << endl;
}
po.clear(); pi.clear();
}
}
}
int q; cin >> q;
while(q--)
{
int x, y; string s;
cin >> x >> y >> s;
if(s[0] == 'a') cout << dp[x][y][3] << endl;
if(s[0] == 'b') cout << dp[x][y][1] << endl;
if(s[0] == 'r') cout << dp[x][y][0] << endl;
if(s[0] == 'l') cout << dp[x][y][2] << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
//cin >> t;
while (t--)
solve();
return 0;
}