K 简单数学+二分..开始带偏了节奏tle 后来看错题wawawa...3人读题想清楚再写题的重要性
C 据说弄懂题意后分情况搞一搞 有点复杂但不难
B 隐藏深的枚举...整数当做32位01 分成32个矩阵分别判断 由于异或运算的唯一解性 数组只要有一个确定 就可以推出每一个元素 所以前2行的异或值可以确定每一个元素 其余值用来check是否可行 类似熄灯问题
题解大都写成2-sat问题..代码长度和用时远高于枚举.. 现场这么多过的 大都也是枚举吧
H dp..又以为是计数了搞一搞发现不可做...僵硬
E 给出一颗树 求一点到其他所有点的每条路径上最小权之和的最大值 并查集+贪心..实现就是排序然后依次加入并查集取max...难在想法..
J 读懂题目后 dfs建树 暴力求最近公共祖先 算法不是太难...转化比较难
D 题意明显的数学题..没什么算法高深的数学分析 就是很复杂
G 很难的字符串处理
可以说是有点坑的赛区..没有明显签到题 其他题也很耐想 铁牌区wa率很高...铜牌区2题 dp还好 枚举不大容易想到...银牌到金牌线智力题...金牌题是复杂数学分类分析和复杂字符串算法
简单题就看错题僵硬好久..铜牌题也没想法瞎搞...前4题get到点都很可做的...
EJ时间够的话也可以搏一搏
然而6题都有金了
补B代码:
#include <cstdio>
#include <cstring>
#include<cmath>
#include <algorithm>
using namespace std;
int a[505][505], b[505][505], x[505], n;
int ok(int q)
{
int i, j;
x[0] = q;
for (i = 1; i < n; i += 2)
x[i] = b[0][i] ^ x[0];
for (i = 2; i < n; i += 2)
x[i] = b[1][i] ^ x[1];
for (i = 0; i < n; i++)
for (j = i + 1; j < n; j++)
if (i % 2 == 0 && j % 2 == 0 && b[i][j] != (x[i] & x[j]))
return 0;
else if (i % 2 && j % 2 && b[i][j] != (x[i] | x[j]))
return 0;
else if ((i + j) % 2 && b[i][j] != (x[i] ^ x[j]))
return 0;
return 1;
}
int main()
{
int i, j, k, f;
while (~scanf("%d", &n))
{
f = 0;
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
scanf("%d", a[i] + j);
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
if ((i == j&&a[i][j]) || a[i][j] != a[j][i])
f = 1;
if (f) { puts("NO"); continue; }
for (k = 0; k < 33; k++)
{
for (i = 0; i < n; i++)
for (j = i + 1; j < n; j++)
b[i][j] = a[i][j] & 1, a[i][j] >>= 1;
if (!ok(0) && !ok(1)) break;
}
puts(k == 33 ? "YES" : "NO");
}
}
H 动态规划:(难点应该是优化时间 hash因子+滚动数组+预处理lcm zoj上不预处理lcm可过 hdu不可过..)
#include <cstdio>
#include <cstring>
#include<cmath>
#include <algorithm>
using namespace std;
#define mm 1000000007
int dp[1005][1005][2], a[1005], lcm[1005][1005];
int gcd(int x, int y)
{
return y ? gcd(y, x%y) : x;
}
void init()
{
int i, j;
for (i = 1; i < 1005; i++)
for (j = 1; j < 1005; j++)
lcm[i][j] = i*j / gcd(i, j);
}
int main()
{
int n, m, x, z, i, j, ii, jj, kk, k;
init();
while (~scanf("%d%d%d", &n, &m, &x))
{
z = 0;
memset(dp, 0, sizeof(dp));
for (i = 1; i <= m; i++)
if (m%i == 0)
a[z++] = i, dp[i][i][0] = 1;
for (i = 1; i < x; i++)
{
for (j = i; j < n; j++)
for (k = 0; k < z; k++)
if (dp[j][a[k]][0])
for (ii = 0; ii < z; ii++)
{
jj = j + a[ii], kk = lcm[a[k]][a[ii]];
if (jj <= n)
dp[jj][kk][1] = (dp[j][a[k]][0] + dp[jj][kk][1]) % mm;
}
for (j = 1; j <= n; j++)
for (k = 0; k < z; k++)
dp[j][a[k]][0] = dp[j][a[k]][1], dp[j][a[k]][1] = 0;
}
printf("%d\n", dp[n][m][0]);
}
}
E 注意答案上界是2*10^10 用longlong 判大小的时候相乘也要加1LL 在zoj因为这个wa一次 :
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct node { int u, v, w; }a[200002];
int u[200002];
long long ans[200002], v;
int find(int x)
{
if (u[x] < 0) return x;
u[x] = find(u[x]);
return u[x];
}
void mix(int x, int y)
{
if ((x = find(x)) == (y = find(y))) return;
if (u[x] < u[y])
u[x] += u[y], u[y] = x;
else
u[y] += u[x], u[x] = y;
}
int cmp(node x, node y)
{
return x.w > y.w;
}
int main()
{
int n, i, x, y, z;
while (~scanf("%d", &n))
{
memset(u, -1, sizeof(u)), memset(ans, 0, sizeof(ans));
for (i = 1; i < n; i++)
scanf("%d%d%d", &a[i].u, &a[i].v, &a[i].w);
sort(a + 1, a + n, cmp);
for (i = 1; i < n; i++)
{
x = find(a[i].u), y = find(a[i].v), z = a[i].w;
v = max(ans[x] + 1LL * z*-u[y], ans[y] + 1LL * z*-u[x]);
mix(a[i].u, a[i].v);
ans[find(a[i].u)] = v;
}
printf("%lld\n", ans[find(1)]);
}
}