A 小苯的xor构造
链接:https://ac.nowcoder.com/acm/contest/115861/A
反应过来:0 ^ X = X,这题就解决了
code
#include<stdio.h>
#include<stdbool.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
#include<math.h>
#include<limits.h>
#define MOD 1000000007
#define mod 998244353
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
// 自定义随机数生成器,避免与标准库冲突
ull xorshift64star(void) {
static ull state = 234;
state ^= state >> 12;
state ^= state << 25;
state ^= state >> 27;
return state * 0x2545F4914F6CDD1DULL;
}
int max_(int p1, int p2) {
return p1 > p2 ? p1 : p2;
}
int min_(int p1, int p2) {
return p1 < p2 ? p1 : p2;
}
int cmp_up(const void* p1, const void* p2) {
return *(int*)p1 - *(int*)p2;
}
int cmp_down(const void* p1, const void* p2) {
return *(int*)p2 - *(int*)p1;
}
int gcd(int a, int b) {
return a % b == 0 ? b : gcd(b, a % b);
}
int lowbit(int x) {
return x & (-x);
}
ll qpow(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
int main() {
int k;
scanf("%d", &k);
printf("%d 0", k);
return 0;
}
B 小苯的权值计算
链接:https://ac.nowcoder.com/acm/contest/115861/B
模拟过程就可以了,不过注意:特殊的,定义 gcd(0, x) = x,所以加个判断即可。
code
#include<stdio.h>
#include<stdbool.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
#include<math.h>
#include<limits.h>
#define MOD 1000000007
#define mod 998244353
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
// 自定义随机数生成器,避免与标准库冲突
ull xorshift64star(void) {
static ull state = 234;
state ^= state >> 12;
state ^= state << 25;
state ^= state >> 27;
return state * 0x2545F4914F6CDD1DULL;
}
int max_(int p1, int p2) {
return p1 > p2 ? p1 : p2;
}
int min_(int p1, int p2) {
return p1 < p2 ? p1 : p2;
}
int cmp_up(const void* p1, const void* p2) {
return *(int*)p1 - *(int*)p2;
}
int cmp_down(const void* p1, const void* p2) {
return *(int*)p2 - *(int*)p1;
}
int gcd(int a, int b) {
return a % b == 0 ? b : gcd(b, a % b);
}
int lowbit(int x) {
return x & (-x);
}
ll qpow(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
int main() {
int n;
scanf("%d", &n);
int a[20];
for(int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
int x = a[0] ^ a[1];
for(int i = 0; i < n - 1; i++) {
a[i] = a[i] ^ a[i + 1];
if(a[i]) x = gcd(x, a[i]);
}
printf("%d", x);
return 0;
}
C 小苯的01矩阵构造
链接:https://ac.nowcoder.com/acm/contest/115861/C
首先明确 k 一定为偶数(改变一个数字其行列都变化,可以自己在纸上模拟),因为 k 在【0, 2*n],所以直接将对角线上 k / 2 的 0 改为 1 即可。
code
#include<stdio.h>
#include<stdbool.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
#include<math.h>
#include<limits.h>
#define MOD 1000000007
#define mod 998244353
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
// 自定义随机数生成器,避免与标准库冲突
ull xorshift64star(void) {
static ull state = 234;
state ^= state >> 12;
state ^= state << 25;
state ^= state >> 27;
return state * 0x2545F4914F6CDD1DULL;
}
int max_(int p1, int p2) {
return p1 > p2 ? p1 : p2;
}
int min_(int p1, int p2) {
return p1 < p2 ? p1 : p2;
}
int cmp_up(const void* p1, const void* p2) {
return *(int*)p1 - *(int*)p2;
}
int cmp_down(const void* p1, const void* p2) {
return *(int*)p2 - *(int*)p1;
}
int gcd(int a, int b) {
return a % b == 0 ? b : gcd(b, a % b);
}
int lowbit(int x) {
return x & (-x);
}
ll qpow(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
int main() {
int n, k;
scanf("%d %d", &n, &k);
if (k % 2 != 0) {
printf("-1\n");
return 0;
}
int a[n][n];
memset(a, 0, sizeof(a));
for (int i = 0; i < k / 2; i++) {
a[i][i] = 1; // 对角线位置设置为 1
}
for (int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
printf("%d", a[i][j]);
}
printf("\n");
}
return 0;
}
D 小苯的重排构造
链接:https://ac.nowcoder.com/acm/contest/115861/D
这道题很有意思,首先特判将不合法的剔除,主要还是要知道最终目的:(num2 - 1) * 2 + num1 + p) == k (p 是 num2 转换为 num1 的个数,其实就是1,2 交替的个数)。代码的实现很优美,值得反复欣赏。
code
#include<stdio.h>
#include<stdbool.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
#include<math.h>
#include<limits.h>
#define MOD 1000000007
#define mod 998244353
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
// 自定义随机数生成器,避免与标准库冲突
ull xorshift64star(void) {
static ull state = 234;
state ^= state >> 12;
state ^= state << 25;
state ^= state >> 27;
return state * 0x2545F4914F6CDD1DULL;
}
int max_(int p1, int p2) {
return p1 > p2 ? p1 : p2;
}
int min_(int p1, int p2) {
return p1 < p2 ? p1 : p2;
}
int cmp_up(const void* p1, const void* p2) {
return *(int*)p1 - *(int*)p2;
}
int cmp_down(const void* p1, const void* p2) {
return *(int*)p2 - *(int*)p1;
}
int gcd(int a, int b) {
return a % b == 0 ? b : gcd(b, a % b);
}
int lowbit(int x) {
return x & (-x);
}
ll qpow(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
int main() {
int n, k;
scanf("%d %d", &n, &k);
int num1 = 0, num2 = 0;
for(int i = 0; i < n; i++) {
int num;
scanf("%d", &num);
if(num == 1) num1++;
else num2++;
}
if(num2 == 0) {
if(n - 1 == k) {
for(int i = 0; i < n; i++) printf("1 ");
} else printf("-1");
return 0;
}
if(num1 == 0) {
if((n - 1) * 2 == k) {
for(int i = 0; i < n; i++) printf("2 ");
} else printf("-1");
return 0;
int max_k = (num2 - 1) * 2 + num1;
int min = min_(num1, num2), max = max_(num1, num2);
int min_k;
if(num1 >= num2 - 1) min_k = n - 1;
else min_k = (num2 - 1) * 2;
if(k < min_k || k > max_k) {
printf("-1");
return 0;
}
int p = 0;
while(((num2 - 1) * 2 + num1 + p) != k) {
num2--;
p++;
}
for(int i = 0; i < n; i++) {
while(num2) {
printf("2 ");
num2--;
i++;
}
printf("1 ");
if(p) {
printf("2 ");
p--;
i++;
}
}
return 0;
}
E 小苯的xor图
链接:https://ac.nowcoder.com/acm/contest/115861/E
这道题我用 链式前向星 装载图(邻接表),然后暴力遍历,发现时间复杂度太大了,超时了,过了50%数据:
code
#include<stdio.h>
#include<stdbool.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
#include<math.h>
#include<limits.h>
#define MOD 1000000007
#define mod 998244353
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
// 自定义随机数生成器,避免与标准库冲突
ull xorshift64star(void) {
static ull state = 234;
state ^= state >> 12;
state ^= state << 25;
state ^= state >> 27;
return state * 0x2545F4914F6CDD1DULL;
}
int max_(int p1, int p2) {
return p1 > p2 ? p1 : p2;
}
int min_(int p1, int p2) {
return p1 < p2 ? p1 : p2;
}
int cmp_up(const void* p1, const void* p2) {
return *(int*)p1 - *(int*)p2;
}
int cmp_down(const void* p1, const void* p2) {
return *(int*)p2 - *(int*)p1;
}
int gcd(int a, int b) {
return a % b == 0 ? b : gcd(b, a % b);
}
int lowbit(int x) {
return x & (-x);
}
ll qpow(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
#define max_n 200000
int head[max_n + 1];
int next[max_n * 2 + 1];
int to[max_n * 2 + 1];
int cnt;
void add(int x, int y) {
next[++cnt] = head[x];
head[x] = cnt;
to[cnt] = y;
}
void built(int n, int m) {
for(int i = 0; i < m; i++) {
int x, y;
scanf("%d %d", &x, &y);
add(x, y);
add(y, x);
}
}
void init() {
cnt = 0;
memset(head, 0, sizeof(head));
memset(next, 0, sizeof(next));
memset(to, 0, sizeof(to));
}
void SUM(int* a, int len, ll* sum, int* w, int k) {
for(int i = 0; i < len - 1; i++) {
int x = a[i];
for(int j = i + 1; j < len; j++) {
int y = a[j];
*sum = (*sum + (w[x] ^ w[k] ^ w[y])) % mod;
}
}
}
int main() {
init();
int n, m;
scanf("%d %d", &n, &m);
int w[n + 1];
for(int i = 1; i <= n; i++) scanf("%d", &w[i]);
built(n, m);
ll sum = 0;
for(int i = 1; i <= n; i++) {
int k = head[i];
int temp[max_n];
int index = 0;
for(; k != 0; k = next[k]) {
temp[index++] = to[k];
}
if(index >= 2) SUM(temp, index, &sum, w, i);
}
printf("%lld", sum);
return 0;
}
所以需要优化 SUM 函数!利用 数学(概率思想) + 位运算 优化。很妙,需要经常温习!
code
#include<stdio.h>
#include<stdbool.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
#include<math.h>
#include<limits.h>
#define MOD 1000000007
#define mod 998244353
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
// 自定义随机数生成器,避免与标准库冲突
ull xorshift64star(void) {
static ull state = 234;
state ^= state >> 12;
state ^= state << 25;
state ^= state >> 27;
return state * 0x2545F4914F6CDD1DULL;
}
int max_(int p1, int p2) {
return p1 > p2 ? p1 : p2;
}
int min_(int p1, int p2) {
return p1 < p2 ? p1 : p2;
}
int cmp_up(const void* p1, const void* p2) {
return *(int*)p1 - *(int*)p2;
}
int cmp_down(const void* p1, const void* p2) {
return *(int*)p2 - *(int*)p1;
}
int gcd(int a, int b) {
return a % b == 0 ? b : gcd(b, a % b);
}
int lowbit(int x) {
return x & (-x);
}
ll qpow(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
#define max_n 200000
int head[max_n + 1];
int next[max_n * 2 + 1];
int to[max_n * 2 + 1];
int cnt;
void add(int x, int y) {
next[++cnt] = head[x];
head[x] = cnt;
to[cnt] = y;
}
void built(int n, int m) {
for(int i = 0; i < m; i++) {
int x, y;
scanf("%d %d", &x, &y);
add(x, y);
add(y, x);
}
}
void init() {
cnt = 0;
memset(head, 0, sizeof(head));
memset(next, 0, sizeof(next));
memset(to, 0, sizeof(to));
}
void SUM(int* a, int len, ll* sum, int* w, int k) {
int cnt0[32] = {0};
int cnt1[32] = {0};
for (int i = 0; i < len; i++) {
int val = w[a[i]];
for (int b = 0; b < 32; b++) {
if ((val >> b) & 1) {
cnt1[b]++;
} else {
cnt0[b]++;
}
}
}
int center_val = w[k];
for (int b = 0; b < 32; b++) {
ll c0 = cnt0[b];
ll c1 = cnt1[b];
ll valid_pairs;
if ((center_val >> b) & 1) {
// 中心位为 1 时,只有邻接点对在该位相同,异或结果才会让该位为 1
// 有效对数量 = C(cnt0, 2) + C(cnt1, 2)
valid_pairs = (c0 * (c0 - 1) / 2) + (c1 * (c1 - 1) / 2);
} else {
// 中心位为 0 时,只有邻接点对在该位不同,异或结果才会让该位为 1
// 有效对数量 = cnt0 * cnt1
valid_pairs = c0 * c1;
}
*sum = (*sum + valid_pairs * (1LL << b) % mod) % mod;
}
}
int main() {
init();
int n, m;
scanf("%d %d", &n, &m);
int w[n + 1];
for(int i = 1; i <= n; i++) scanf("%d", &w[i]);
built(n, m);
ll sum = 0;
for(int i = 1; i <= n; i++) {
int k = head[i];
int temp[max_n];
int index = 0;
for(; k != 0; k = next[k]) {
temp[index++] = to[k];
}
if(index >= 2) SUM(temp, index, &sum, w, i);
}
printf("%lld", sum);
return 0;
}
F 小苯的前缀gcd构造
链接:https://ac.nowcoder.com/acm/contest/115861/F
还是有难度的,通过 剪枝 + 预处理 大幅度优化,枚举 gcd 进行深搜,思想以及代码实现很值得学习,题目质量很高!
code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 预先生成每个数的因数列表,g[i] 存储 i 的所有因数(除自身外,从小到大)
int g[51][51];
int g_len[51];
// 初始化因数列表
void init_g() {
for (int i = 1; i <= 50; i++) {
g_len[i] = 0;
for (int j = 1; j <= i; j++) {
if (i % j == 0) {
g[i][g_len[i]++] = j;
}
}
}
}
// 深度优先搜索函数,寻找满足条件的数组
int find(int n, int m, int x, int *result, int index, int current_sum, int current_gcd) {
if (index == n) return current_sum == x ? 1 : 0;
// 剪枝:如果当前已选元素个数为 index,剩余需要选 n - index 个元素
int remaining = n - index;
int max_possible = current_sum + current_gcd * remaining;
int min_possible = current_sum + 1 * remaining;
if (max_possible < x || min_possible > x) {
return 0;
}
// 遍历当前可能的因数
for (int i = 0; i < g_len[current_gcd]; i++) {
int next_gcd = g[current_gcd][i];
int next_num = next_gcd;
result[index] = next_num;
if (find(n, m, x, result, index + 1, current_sum + next_gcd, next_gcd)) {
return 1;
}
}
return 0;
}
int main() {
init_g();
int T;
scanf("%d", &T);
while (T--) {
int n, m, x;
scanf("%d %d %d", &n, &m, &x);
// 剪枝条件1:如果 x < n,直接无解,因为每个元素至少贡献 1(gcd 至少是 1 ,对应元素至少是 1 )
if (x < n) {
printf("-1\n");
continue;
}
// 剪枝条件2:如果 x % n == 0,且 x / n <= m ,直接构造全 x/n 的数组
int avg = x / n;
if (x % n == 0 && avg <= m) {
for (int i = 0; i < n; i++) {
printf("%d ", avg);
}
printf("\n");
continue;
}
int *result = (int *)malloc(n * sizeof(int));
// 调整初始 current_gcd 的尝试范围,从可能的较大值开始,增加找到解的概率
// 这里先尝试从 min(m, x) 开始往下找合适的初始 gcd
int initial_gcd;
for (initial_gcd = fmin(m, x); initial_gcd >= 1; initial_gcd--) {
memset(result, 0, n * sizeof(int));
if (find(n, m, x, result, 0, 0, initial_gcd)) {
for (int i = 0; i < n; i++) {
printf("%d ", result[i]);
}
printf("\n");
free(result);
goto here; // 找到解,处理下一个测试用例
}
}
// 所有初始 gcd 尝试都失败,输出 -1
printf("-1\n");
free(result);
here:;
}
return 0;
}