虽然参加了青岛icpc但那场的题超出我太多..唯一赛后弄会的polya计数已经写到上一篇了...
但沈阳的题目还好比较常规 中等题尤其多
I Little Boxes
签到题目 a+b+c+d 小坑点是小于等于2^62 就是说答案小于等于2^64
特判一下和为2^64情况用unsigned long long就好(或者java)
各水平的队伍都有不是1A的..所以还是认真点..20罚时兴许就换一块奖牌
#include
#include
int main()
{
unsigned long long a, b, c, d;
int t;
scanf("%d", &t);
while (~scanf("%llu%llu%llu%llu", &a, &b, &c, &d))
if (a == b&&b == c&&c == d&&d == 4611686018427387904)
printf("%s\n", "18446744073709551616");
else
printf("%llu\n", a + b + c + d);
}
K Rabbits
签到题 一群兔子在数轴上 每只兔子每次可以向内跳过1只兔子 问最多跳几次
数轴上所有兔子之间的空隙减去2边最小的空隙就是最多跳的次数...
#include
#include
#include
using namespace std;
int a[505], n, t;
int main()
{
int i, ans;
scanf("%d", &t);
while (t--&&scanf("%d", &n))
{
ans = 0;
for (i = 1; i <= n; i++)
scanf("%d", a + i);
for (i = 2; i <= n; i++)
ans += (a[i] - a[i - 1] - 1);
ans -= min(a[n] - a[n - 1] - 1, a[2] - a[1] - 1);
printf("%d\n", ans);
}
}
第三题开始就不太水了..
L Tree
题意有点麻烦...给一个树 n种染色 染节点(每个节点唯一染色) 每种染色取出这种颜色的点的最小生成树中的边 求这n个边集的交的集合最多有几个边
有点头大的感觉..
正解是如果1条边的2侧的节点数都大于等于n 则可以把这个边2侧的点染成每侧都有n种颜色 这条边就可以在最终集合里且不影响其他边 ans++
记忆化搜索(dfs)出个节点以下(包括自己)的节点数ch[i] 如果ch[i]>=n且剩下的点数>=n 则ans++
复杂度对节点数是线性的
代码也很好写 难怪有队伍22分钟出了前三题...
#include
#include
#include
using namespace std;
struct { int v, ne; }a[400002];
int k1, h[200002], ch[200002], vi[200002];
void add(int u, int v)
{
a[k1].v = v, a[k1].ne = h[u], h[u] = k1++;
}
int dfs(int x)
{
if (ch[x] != 0)
return ch[x];
int i, ans = 1;
vi[x] = 1;
for (i = h[x]; i; i = a[i].ne)
if (vi[a[i].v] == 0)
ans += dfs(a[i].v);
return ch[x] = ans;
}
int main()
{
int t, i, n, k, x, y, ans;
scanf("%d", &t);
while (t--&&scanf("%d%d", &n, &k))
{
memset(h, 0, sizeof(h)), k1 = 1;
memset(ch, 0, sizeof(ch)), ans = 0;
memset(vi, 0, sizeof(vi));
for (i = 1; i < n; i++)
scanf("%d%d", &x, &y), add(x, y), add(y, x);
dfs(1);
for (i = 1; i <= n; i++)
{
ch[i] = dfs(i);
if (ch[i] >= k&&n - ch[i] >= k)
ans++;
}
printf("%d\n", ans);
}
}
F Heron and His Triangle
题意简明 如果三角形三边为t-1,t,t+1且三角形面积是整数 则这个数叫xxx数
求大于等于x的xxx数(10^30)
可以规约到求一个双曲线整点的问题 沉迷于数学分析然而并分析不出来...mathematica分析少了一半的解导致wa..
Acm解法是打表出前几个找规律...答案类似斐波那契的a[i]=4*a[i-1]-a[i-2] 然后java大数一发(c++打表代码写的很难看..)
其实可以规约到一个序列的问题大都是这么做:打表出前几项 通常是斐波那契类似的递推公式 范围不够打表的话可以矩阵快速幂算
#include
#include
#include
#include
using namespace std;
char ans[100][100] = { "4", "14", "52", "194", "724", "2702", "10084", "37634", "140452", "524174", "1956244",
"7300802", "27246964", "101687054", "379501252", "1416317954", "5285770564",
"19726764302", "73621286644", "274758382274", "1025412242452", "3826890587534",
"14282150107684", "53301709843202", "198924689265124", "742397047217294",
"2770663499604052", "10340256951198914", "38590364305191604",
"144021200269567502", "537494436773078404", "2005956546822746114",
"7486331750517906052", "27939370455248878094", "104271150070477606324",
"389145229826661547202", "1452309769236168582484",
"5420093847118012782734", "20228065619235882548452",
"75492168629825517411074", "281740608900066187095844",
"1051470266970439230972302", "3924140458981690736793364",
"14645091568956323716201154", "54656225816843604128011252",
"203979811698418092795843854", "761263020976828767055364164",
"2841072272208896975425612802", "10603026067858759134647087044",
"39571031999226139563162735374", "147681101929045799118003854452",
"551153375716957056908852682434", "2056932400938782428517406875284",
"7676576228038172657160774818702", "28649372511213908200125692399524" }
;
int BigCmp(char * a, char * b) // 大数a < 大数b 返回1 ,相等返回0 ,a>b返回-1
{
int i, j, k;
int la = strlen(a), lb = strlen(b);
char * temp;
if (a[0] == '-' && b[0] != '-')
return 1;
else if (a[0] != '-' && b[0] == '-')
return -1;
else if (a[0] == '-' && b[0] == '-')
{
a++, b++;
temp = a, a = b, b = temp;
la--, lb--;
k = la, la = lb, lb = k;
}
if (la < lb)
return 1;
if (la > lb)
return -1;
if (la == lb)
{
for (i = 0; i < la; i++)
{
if (a[i] < b[i])
return 1;
else if (a[i] > b[i])
return -1;
}
}
return 0;
}
int main()
{
int t; scanf("%d", &t);
while (t--)
{
char s[100];
scanf("%s", s);
for (int i = 0; i < 55; i++)
if (BigCmp(s, ans[i])!=-1)
{
printf("%s\n", ans[i]);
break;
}
}
}
这是前4题,全做出的大部分铜牌剩下的没牌...
G Infinite Fraction Path
题意很明确 给一长度为n的字符串 每个点从i有一条通往(i*i)%n的路 求长度为n的通路中的字典序最大的(数字最大)
一个一个字符串的话找遇到最坏情况(所有字符一样)复杂度O(n^2) 考虑bfs按层搜索优化
首先第一个点肯定是最大的字符 让这些点入队 每层最大的数才继续搜下个节点 再去除每层的重复节点(很重要 所有字符一样的时候靠它优化)
算法就是上面一句 实现稍复杂 每次让队列中层数最小的中数字最大的派生下个节点 需要用优先队列 去重节点可以用栈模拟set或直接set(但这里直接用set会tle...)
主要卡的是大多数字符一样是时候的时间 复杂度比较玄学..感觉和(i*i)%n这个式子有关...最后应该是在一个环中的循环 或许环是O(n^0.5)? 总复杂度是O(n^1.5)?
#include
#include
#include
#include
using namespace std;
char a[150005], ans[150005];
int sta[150005], top, la, bo[150005];
struct node {
int in, step;
node() {}
node(int in, int step)
{
this->in = in, this->step = step;
}
};
priority_queue<node>que;
bool operator<(node A, node B)
{
if (A.step == B.step)
return a[A.in] < a[B.in];
return A.step > B.step;
}
int main()
{
int t, n, i, ca = 1;
char ma;
node x;
scanf("%d", &t);
while (t--&&scanf("%d%s", &n, a))
{
memset(ans, 0, sizeof(ans)), ma = 0, top = 0;
memset(sta, 0, sizeof(sta)), memset(bo, 0, sizeof(bo));
for (i = 0; i < n; i++)
ma = max(ma, a[i]);
ans[0] = ma, la = 0;
for (i = 0; i < n; i++)
if (a[i] == ma)
que.push(node(i, 0));
while (!que.empty())
{
x = que.top(), que.pop();
if (x.step >= n)continue;
if (x.step > la)
{
la = x.step;
while (top)
bo[sta[--top]] = 0;
}
if (ans[la] > a[x.in] || bo[x.in] == 1)continue;
sta[top++] = x.in, bo[x.in] = 1;
ans[la] = a[x.in];
que.push(node((1LL * x.in*x.in + 1) % n, x.step + 1));
}
printf("Case #%d: %s\n", ca++, ans);
}
return 0;
}
M Wandering Robots
面向样例编程系列...
题意很恶心 其实是:每个点的权值是它四周好点的个数+1 坏点权值为0 求总权值和x+y>=n的点的权值的比
翻译好题目就不是太难了 一个需要注意的是如果一个区域全部被围起来 这个区域内所有的点都是坏点(类似hdu5925) 但测试数据中并没有这样的...
数据范围有点大 但坏点不多 先离散化 然后搜索看哪些点是不可达原点的 再统计答案
复杂度大概是4*k^2
但数据很水没有被围起来的点...所以一个一个坏点及其周围的点更新就好..复杂度O(K)
C Empty Convex Polygons
字面意思 最大空凸包
虽然是金牌题 但红书上有完全一样的模板..所以几个队伍因为出了这题4题得铜 题目模板什么的还是应该多看看
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 100;
const double zero = 1e-8;
struct Vector {
double x, y;
};
inline Vector operator - (Vector a, Vector b)
{
Vector c;
c.x = a.x - b.x;
c.y = a.y - b.y;
return c;
}
inline double Sqr(double a) {
return a*a;
}
inline int Sign(double a) {
if (fabs(a) <= zero) return 0;
return a<0 ? -1 : 1;
}
inline bool operator < (Vector a, Vector b)
{
return Sign(b.y - a.y) >0 || Sign(b.y - a.y) == 0 && Sign(b.x - a.x)>0;
}
inline double Max(double a, double b) {
return a>b ? a : b;
}
inline double Length(Vector a)
{
return sqrt(Sqr(a.x) + Sqr(a.y));
}
inline double Cross(Vector a, Vector b) {
return a.x*b.y - a.y*b.x;
}
Vector dot[maxn], List[maxn];
double opt[maxn][maxn];
int seq[maxn];
int n, len;
double ans;
bool Compare(Vector a, Vector b) {
int temp = Sign(Cross(a, b));
if (temp != 0) return temp>0;
temp = Sign(Length(b) - Length(a));
return temp>0;
}
void Solve(int vv) {
int i, j, t, _len;
for (i = len = 0; i
if (dot[vv]<dot[i]) List[len++] = dot[i] - dot[vv];
for (i = 0; i
for (j = 0; j
opt[i][j] = 0;
sort(List, List + len, Compare);
double v;
for (t = 1; t
_len = 0;
for (i = t - 1; i >= 0 && Sign(Cross(List[t], List[i])) == 0; i--);
while (i >= 0) {
v = Cross(List[i], List[t]) / 2;
seq[_len++] = i;
for (j = i - 1; j >= 0 && Sign(Cross(List[i] - List[t], List[j] - List[t]))>0; j--);
if (j >= 0) v += opt[i][j];
ans = Max(ans, v);
opt[t][i] = v;
i = j;
}
for (i = _len - 2; i >= 0; i--)
opt[t][seq[i]] = Max(opt[t][seq[i]], opt[t][seq[i + 1]]);
}
}
int i;
double Empty()
{
ans = 0;
for (i = 0; i
Solve(i);
return ans;
}
int main()
{
int t; scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%lf%lf", &dot[i].x, &dot[i].y);
}
double ans = Empty();
printf("%.1lf\n", ans);
}
return 0;
}