【题目大意】
给一个弦图。问色数是多少。
【算法】
先是有显然的定理:色数(用最少种颜色涂满图中的点,使得每条边两端的点颜色都不同)>=团数(最大团的点数)
因为是弦图,由完美消除序列的性质可以构造得色数=团数,于是达到下界。
于是直接利用完美消除序列的性质求出团数即可。
【其它】
完美消除序列的性质是:
对于序列中第i个点Vi。
令S={Vj | (j>i) && ((Vi,Vj) in E)},那么S+Vi成一个团。
>.<还是V^2。虽然O(V+E)也不难写。求不鄙视。
【CODE】
【题目大意】
给一个弦图。问色数是多少。
【算法】
先是有显然的定理:色数(用最少种颜色涂满图中的点,使得每条边两端的点颜色都不同)>=团数(最大团的点数)
因为是弦图,由完美消除序列的性质可以构造得色数=团数,于是达到下界。
于是直接利用完美消除序列的性质求出团数即可。
【其它】
完美消除序列的性质是:
对于序列中第i个点Vi。
令S={Vj | (j>i) && ((Vi,Vj) in E)},那么S+Vi成一个团。
>.<还是V^2。虽然O(V+E)也不难写。求不鄙视。
【CODE】
>____<觉得必要记录一下。
使用WC2009 CDQ PTT的最大势方法标号,然后check。O(n^2)的。
【弦图】不存在环满足(长度大于3)&&(环上任意非相邻点间无边) 的一个图。
【CODE】https://ideone.com/8QX5e
>.<深切感受到自己蒟蒻。
250题意
N,M<=10^9
i=N;
j=M;
while (j<=lcm(N,M)){
while (i ans+=j-i; j+=M; } return (double)ans/(lcm(N,M)/M);(平均数) 、 然后发现其实每次j-i都是gcd(N,M)的倍数,设g=gcd(N,M),然后j-i刚好是0,g,2*g,3*g,…,(lcm(N,M)/M-1)*g 、 lcm(N,M)/M=N/g 于是ans=(N/g)*(N/g-1)/2 * g / (N/g) 然后最终代码是
int gcd(int x,int y){return y?gcd(y,x%y):x;}
double Starport::getExpectedTime(int N, int M) {
long long g=gcd(N,M);
long long t=N/g;
return g*(t*(t-1)/2)/(double)(t);
}
550
弄完以后交FST了….
题目大意就是给定一组字典,再给出一个字符串,让你用手机T9的方式最少要多少次按键把字符串打出来。
对我来说很考验coding啊>.<...
思路不太难,就模拟每次弄一个字典里字符的前缀。然后由于是类似栈的形式,只能从后面删和插入,所以可以F[i]表示前i个弄好最少多少次按键,然后弄个邻接矩阵mat[i][j]表示两两状态间转移最少需要多少步.
最后来个floyd就OK…
个中细节和处理技巧多多= =,请自行体会。。。
2Y。
被屠什么的,无所谓的。
考完试以后coding感觉各种水.
通常都是想到写不出的样子.
记得watashi说过,想出算法算什么呢,能AC才是真本事.
ACM和OI不一样,速度很重要.
OI中对于一般人的可捉题,如果想出算法,要coding出来一般还是没有太大问题的.
而且通常对拍完时间都还是够的.
ACM难道你还会写个程序对拍吗?
基本都是眼看的吧…
训练OI,也许该不停地切掉1000pt. AK各种省选题.
训练ACM,至少在我这个层次而言,Target应该是比较稳定地搞掉250pt和500pt. 至少先做到这样吧.
1000pt即使能想到,也几乎都不能在现场出掉
当然,不会的skill和algorithm也是必须学的.
总之,先坚持每天practice一场SRM或者CF或者直接做一场比赛.
至少把250和500写短,快速弄对吧.
该出的题都出不了,那凭什么去弄神题呢…
…欢迎各位鄙视和指点.
完爆…挫死了.在被屠中成长.
A
可知周期只能是lcm(a,b),而lcm=a*b/gcd(a,b),所以更替不会超过a+b次,于是直接模拟优先者的更替,计算时间比较即可。
B
模拟题。虽然这题很弱,但是给了我教训。
注意对于map C 做的时候头一热,SG都没算直接用胜负表示状态…NIM游戏转化为有向图的模型里面,如果只有一个棋子乱走确实可以这样,但是多个棋子走就必须SG函数了…犯傻了… 本题不只是多个棋子一起走,而且每个棋子还会分裂。但是我们依然可以得出这个性质:若该状态本身各棋子xor和为0,那么无论对方下一步怎么走,我还是能使得xor和为0(NIM游戏的证明方法)。 于是SG+异或前缀和。枚举决策是O(sqrt(n))的,总复杂度O(n*sqrt(n))
#include #include #include #include #include using namespace std; const int N=100005; int sg[N]; int best[N]; int Sum[N]; set int main(){ int n; cin >> n; Sum[0]=0; sg[0]=1; fill(best+1,best+n+1,-1); for (int i=1;i<=n;i++){ Hash.clear(); for (int k=2;(k+1)*k/2<=i;k++){ int base=(i-(k+1)*k/2); if (base%k) continue; base/=k; if ( (Sum[base+k]^Sum[base])==0 ) if (best[i]==-1) best[i]=k; Hash.insert(Sum[base+k]^Sum[base]); } for (int j=0;;j++) if (!Hash.count(j)) { sg[i]=j; break; } Sum[i]=Sum[i-1]^sg[i]; } cout << best[n] << endl; } D 给一棵树,每条边有权值。n<=10^5 每两个点之间都会打一次架(A打了B,B还要打一次A),打架以后会在路径上边权最大的边上种树。如果多条最大边,每条都种树。 问最多树的是哪些路? 按边从小到大排序,然后逐次合并点块。如果没有同权的边,这个方法就很容易用并查集实现。然后现在我们考虑同权的一块处理,因为之前的小的都合过点了,现在加了一堆同权的边以后,会构成多颗新树。然后分别对这些树DFS求出子树大小然后乘一下就得解。 时间复杂度O(n lg n) #include #include #include #include #include #include