1957(div2)
A. Stickogon
给你长度为
- 多边形的每条边都正好由一根木棒组成。
- 多边形中使用的小棒不超过
根。
注意:木棒不能折断。
忘记将 n 修改为 100 了
void solve() {
int n;cin >> n;vector<int> a(110);
for (int i = 1;i <= n;i++) {
int x;cin >> x;a[x]++;
}
int cnt = 0;
for (int i = 1;i <= 100;i++) {
cnt += a[i] / 3;
}
cout << cnt << '\n';
}
B. A BIT of a Construction
给定整数
- 使
的二进制表示中 的个数最大。
void solve() {
int n, k;cin >> n >> k;
if (n == 1) {
cout << k << "\n";return;
}
bitset<32> b(k);
int x = 0;
for (int i = 31;i >= 0;i--) {
if (b[i]) {
x = (1ll << i);break;
}
}
x--;
int y = k - x;
cout << x << " " << y << " ";
for (int i = 2;i < n;i++)cout << "0 ";
cout << '\n';
}
C . How Does the Rook Move?
给您一个
有效的一步棋是将一只车放在一个位置(
你先开始,当你在自己的回合中走了一步有效的棋,将白车置于位置(
您已经与计算机下了
如果存在一个坐标(
Solution
组合数学/DP
法一:DP 转移方程:f[i] = f[i - 1] + f[i - 2] * 2 * (i - 1)
若从后往前推:
对于棋下在对角线上时,选择
若没有下在对角线上:选定该行
#define int long long
constexpr int mod = 1e9 + 7;
int f[300010];
void solve() {
int n, k;cin >> n >> k;int cnt = n;
for (int i = 1;i <= k;i++) {
int x, y;cin >> x >> y;cnt -= 2 - (x == y);
}
cout << f[cnt] << '\n';
}
signed main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
f[0] = 1;f[1] = 1;f[2] = 3;
for (int i = 3;i <= 3e5;i++) {
f[i] = f[i - 1] + f[i - 2] * 2 * (i - 1);f[i] %= mod;
}
int _ = 1;
cin >> _;
while (_--)
solve();
}
组合数学:
不懂是如何推出的
#define int long long
constexpr int mod = 1e9 + 7;
int fac[300010];
int inv(int a, int b = mod - 2) {
int ans = 1;
while (b) {
if (b & 1)ans = (ans * a) % mod;
a = (a * a) % mod;b >>= 1;
}
return ans;
}
int c(int a, int b) {
return fac[a] * inv(fac[a - b]) % mod * inv(fac[b]) % mod;
}
void solve() {
int n, k;cin >> n >> k;int cnt = n;
for (int i = 1;i <= k;i++) {
int x, y;cin >> x >> y;cnt -= 2 - (x == y);
}
int ans = 0;
for (int i = 0;i * 2 <= cnt;i++) {
ans = (ans + c(cnt, 2 * i) * c(2 * i, i) % mod * fac[i]) % mod;
}
cout << ans << '\n';
}
signed main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
fac[0] = fac[1] = 1;
for (int i = 2;i <= 3e5;i++) {
fac[i] = fac[i - 1] * i % mod;
}
int _ = 1;
cin >> _;
while (_--)
solve();
}
D . A BIT of an Inequality
给你一个数组
, 和 .
定义
Solution
位运算
设前缀异或为
, 代表前 个数进行异或。 则可以将要求简化为求
的个数。 现在进行分类讨论:设
当前比特位分别为 , 代表的是 最高比特位的值 当
时:无论 为 , 的值都不会变 当
时,若此时 的值不同,则最终的值会变小,否则最终的值会变大
总结:变大的情况只有
这样对于
由题目可得
即
1 的数量算出来之后,这个区间 0 的数量就是区间长度减去 1 的数量。
#define int long long
int c[32][100010];
void solve() {
int n;cin >> n;vector<int> a(n + 1), s(n + 1);
for (int i = 1;i <= n;i++) {
cin >> a[i];s[i] = s[i - 1] ^ a[i];
for (int j = 0;j <= 30;j++) {
c[j][i] = c[j][i - 1] + (s[i] >> j & 1);
}
}
int ans = 0;
for (int i = 1;i <= n;i++) {
int k = __lg(a[i]);
ans += (c[k][n] - c[k][i - 1]) * c[k][i - 1];
ans += (n - i + 1 - (c[k][n] - c[k][i - 1])) * (i - c[k][i - 1]);
}
cout << ans << '\n';
}
现在只需要进行预处理:需要得到的是
这里需要处理其前缀与后缀:(官方题解)
pre[i][j][k = 0]
代表个数的第 位是 的个数, 同理。
suf[i][j][k = 0]
代表个数的第 位是 的个数, 同理。 注意:由于这里没有错位的进行前缀与后缀计算,所以在对
进行操作时,需要将 归于
constexpr int Z = 30, MAX_N = 1e5 + 3;
int pref[Z][MAX_N][2];
int suff[Z][MAX_N][2];
void solve() {
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 0; i < Z; i++) suff[i][n + 1][0] = suff[i][n + 1][1] = 0;
for (int i = 0; i < Z; i++) {
for (int j = 1; j <= n; j++) {
int t = (a[j] >> i) & 1;
for (int k = 0; k < 2; k++) pref[i][j][k] = (t == k) + pref[i][j - 1][k ^ t];
}
for (int j = n; j >= 1; j--) {
int t = (a[j] >> i) & 1;
for (int k = 0; k < 2; k++) suff[i][j][k] = (t == k) + suff[i][j + 1][k ^ t];
}
}
long long ans = 0;
for (int i = 1; i <= n; i++) {
int z = __lg(a[i]); // <-> 31 - __builtin_clz(a[i])
ans += 1ll * pref[z][i - 1][1] * (1 + suff[z][i + 1][0]);
ans += 1ll * (1 + pref[z][i - 1][0]) * suff[z][i + 1][1];
}
cout << ans << "\n";
}
E. Carousel of Combinations
给你一个整数
求
由于这个值可能非常大,因此求它的模数
Solution
威尔逊定理
容易知道
可以知道的是
定理:对于素数 , ,对于合数 ,
这里利用差分数组
#define int long long
constexpr int N = 1e6, mod = 1e9 + 7;
int vis[N + 10], pri[N + 10], isp[N + 10];//判断是否是素数
int d[N + 10];
void init(int n) {//线性筛
int cnt = 0;
for (int i = 2; i <= n; ++i) {
if (!vis[i]) {
pri[cnt++] = i;isp[i] = 1;
}
for (int j = 0; j < cnt; ++j) {
if (i * pri[j] > n) break;
vis[i * pri[j]] = 1;
if (i % pri[j] == 0) break;
}
}
}
signed main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
init(N);
for (int j = 2;j <= N;j++) {
if (j == 4 || isp[j]) {
int v = (j == 4 ? 2 : j - 1);
for (int i = j;i <= N;i += j) {//枚举j的倍数
int t = v * (i / j) % j;
d[i] = (d[i] + t) % mod;
if (i + j <= N)d[i + j] = (d[i + j] - t + mod) % mod;
}
}
}
for (int i = 1;i <= N;i++)d[i] = (d[i] + d[i - 1]) % mod;
for (int i = 1;i <= N;i++)d[i] = (d[i] + d[i - 1]) % mod;
int _;cin >> _;
while (_--) {
int n;cin >> n;cout << d[n] << '\n';
}
}