H 签到概率题 推公式输入输出
B 求因子+进制转换 没什么难点 认真写就好
A 麻将胡牌..可怕的模拟
C wa了无数发的dp...结果基本思路就错了而且不知道错在哪...
E 数学知识 贪心+判连通 比较新奇..
F 后缀自动机...很正经的难题
K 复杂数据结构 splay伸展树
I 数学解复杂方程+最小区间覆盖...
这场层次不错 铜金之间尤其好 6题全是金5题是全银..题目也比较正
C dp又错..好像是后效性的锅..还没想太明白..这种时限比其他题长的 复杂度肯定不会太小O(n)注定会wa..
正解是常数小的50*O(n*10^4) 算下来是常数小的5亿了...
这个e就很有趣...虽然是数学(等比数列求和)+贪心+判连通 但并没有什么算法...
贪心就是for循环
判连通时 对于有加油站的点 如果它离最近的加油站距离超过d 则不连通(注意只有一个加油站的情况) 对于没有加油站的点 如果它离最近的加油站距离超过d/2(不能走一个来回) 则不连通
总共for+if就能写完 而且没有什么神奇的操作 就是不好想到...
复杂度O(n^3) 显然不是卡时间的题
代码:
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int mp[133][133], n, d, po[133][2], a[133];
int fx(int x, int y, int xx, int yy)
{
return ceil(sqrt((xx - x)*(xx - x) + (yy - y)*(yy - y)));
}
int ok()
{
int mm, i, j, f;
for (i = 0; i < n; i++)
if (a[i] == 1)
{
for (j = f = 0, mm = 1 << 28; j < n; j++)
if (j != i&& a[j] == 1)
mm = min(mm, mp[i][j]), f = 1;
if (f&&mm > d) return 0;
}
else
{
for (j = 0, mm = 1 << 28; j < n; j++)
if (a[j] == 1) mm = min(mm, mp[i][j]);
if (mm > d / 2) return 0;
}
return 1;
}
int main()
{
int i, j, mm;
while (~scanf("%d%d", &n, &d))
{
for (i = 0; i < n; i++)
scanf("%d%d", po[i], po[i] + 1), a[i] = 1;
for (i = 0; i < n; i++)
for (j = i + 1; j < n; j++)
mp[i][j] = mp[j][i] = fx(po[i][0], po[i][1], po[j][0], po[j][1]);
for (i = 0; i < n; i++)
{
for (j = 0, mm = 1 << 28; j < n; j++)
if (j != i) mm = min(mm, mp[i][j]);
if (mm > d) { puts("-1"); break; }
}
if (i != n) continue;
for (i = n - 1; i > 0; i--)
{
a[i] = 0;
if (ok() == 0) a[i] = 1;
}
i = n - 1;
while (!a[i]) i--;
for (; i >= 0; i--)
printf("%d", a[i]);
puts("");
}
}
C 动态规划总是给出正解能知道正解是对的 但想不到自己为什么错的...
不过这题正解的思路竟然意外简单 依次枚举所有转的可能 从左向右的话 固定1格 它左边的格该次转的次数总是非递增的 复杂度刚刚好
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[1005][13][13], n, i, j, p, q, k, tmp;
char a[1005], b[1005];
int main()
{
while (~scanf("%s%s", a, b))
{
memset(dp, 63, sizeof(dp));//初始化为一个很大的数(不是63)
dp[0][0][0] = 0, n = strlen(a);
//dp[i][j][k]表示前i位相同且第i+1位增加为j ,i+2位增加为k的时对应的最小转动次数
for (i = 0; i < n; i++)
for (j = 0; j < 10; j++)
for (k = 0; k < 10; k++)
{
tmp = (b[i] - a[i] - j + 20) % 10;
//达到j时需要向上转的次数 +20为了保证括号内是正数
for (p = 0; p <= tmp; p++)
for (q = 0; q <= p; q++)
dp[i + 1][(k + p) % 10][q] = min(dp[i + 1][(k + p) % 10][q], dp[i][j][k] + tmp);
//p q分别是i+1,i+2转的次数 i+2的次数小于等于i+1
tmp = 10 - tmp;//向下
for (p = 0; p <= tmp; p++)
for (q = 0; q <= p; q++)
dp[i + 1][((k - p) % 10 + 10) % 10][(10 - q) % 10] = min(dp[i + 1][((k - p) % 10 + 10) % 10][(10 - q) % 10], dp[i][j][k] + tmp);
}
printf("%d\n", dp[n][0][0]);
}
}