作为杭电三队,我和大三学长陈钦况,还有大一便进过WF的周贤杰组队。踏上了前往沈阳的行程。本来以平时训练的成绩,我们的期望是争金,最后却只打了个铜回来。着实是很意外,很遗憾。然而却有很多值得总结的经验和许多要吸取的教训,为我今后的比赛做准备。
比赛重现:
第20分钟,队友AC掉D题。
D题——
【题意】
共有T([1,500])组数据。
每组数据有1~n([2,20000])共n个正整数。
一开始对于已有数字集合,除了a,b(1<=a,b<=n && a≠b),其他数字都是不存在的。
对于每次成功的操作,我们是从已有数字集合之中,任选两个不同数x,y,得到z=x-y或者z=x+y,如果z是在[1,n]范围,而且z这个数字当前不存在,那我们就可以得到这个新数z,并把其放入已有数字集合之中。
Yuwgna先手,Iaka后手,谁无法操作谁就输了。问你最后的winner是谁。
【类型】
签到 博弈 gcd
【分析】
首先应该想的问题是,数轴的范围是[1,n],但是我们能选的数究竟有什么呢?
样例中的{3 1 3}{8 6 8}这样组数据,前者可以取遍1,2,3,后者却只能取得2,4,6,8,让我们很快想到实际能选取的数字范围要由gcd判定。
我们先令g=gcd(x,y),那显然我们能取的数,必然是g的倍数。
于是求出,接下来能取的数的个数num=n/g-2
所以答案就是——
【时间复杂度&&优化】
O(Tlogn)
【trick&&吐槽】
这道题之所以给了这么多样例,就是为了让这题的结论更容易观察,让这题更算得上是签到题。
【数据】
input
16
2 1 2
3 1 3
67 1 2
100 1 2
8 6 8
9 6 8
10 6 8
11 6 8
12 6 8
13 6 8
14 6 8
15 6 8
16 6 8
1314 6 8
1994 1 13
1994 7 12
output略
【代码】
int gcd(int x,int y)
{
return y==0?x:gcd(y,x%y);
}
int main()
{
scanf("%d",&casenum);
for(casei=1;casei<=casenum;casei++)
{
int n,a,b;
scanf("%d%d%d",&n,&a,&b);
printf("Case #%d: %s\n",casei,(n/gcd(a,b))&1?"Yuwgna":"Iaka");
}
return 0;
}
===========================================================
第50分钟,我AC掉M题。
M题——
【题意】
两个人A,B想要见面。
有n([2,1e5])个点,A初始在1点,B初始在n点。
有m个集合关系,第i个集合有Si个点,这些点两两之间移动所花费的时间都为dis([1,1e9]),有∑Si<=1e6。
让你输出A和B在哪些点碰面,使得他们能在最早时间相遇。
输出这个最早相遇时间以及所有满足的点。
【类型】
最短路
【分析】
这题很显然是一个最短路模型。然而如果暴力建边,边数可达1e12条,爆炸。
问题是怎么处理集合关系。比较好想,我读完题的瞬间就想到了做法——拆点。
对每个集合构造两个点,入点和出点,之间连一条边权为dis的边,
把集合内的每个点向这个集合的入点连边,边权为0,
把集合的出点向这个集合内的每个点连边,边权为0。
这样就实现了,对于每个集合,利用2Si+1条边,改变其内任意两个点的边权都为dis。
然后分别以1和n为起点,跑最短路,然后扫描一下即可。
【时间复杂度&&优化】
O(mlogm)
【trick&&吐槽】
点数N=n+2*最大集合数=1e5+2e6
边数M=3*最大集合数=3e6
【数据】
input
2
5 4
1 3 1 2 3
2 2 3 4
10 2 1 5
3 3 3 4 5
3 1
1 2 1 2
output
Case #1: 3
3 4
Case #2: Evil John
【代码】
const int N=1e5+2e6+10,M=3e6+10,Z=1e9+7,ms63=1061109567;
int casenum,casei;
int id;
int first[N],w[M],c[M],nxt[M];
LL f[N],F[N];
bool e[N];
struct node
{
int x;LL v;
node(){}
node(