Time 7:50 AM to 11:15 AM 2016 10 25 AM
题目:http://files.cnblogs.com/files/CtsNevermore/1025problem.pdf
试题包:http://files.cnblogs.com/files/CtsNevermore/10-27-16%E5%B9%B410%E6%9C%8825.zip
据说是数学专题考试,然而最后混进来一个不知道哪来的暴力 + hash,,,都是套路,,,
个人感觉:1、斐波拉契无比受欢迎= = 2、打表无比重要= =
解题报告:
1、看到第一题没什么思路,果断的先打了暴力,然后看着几万行的out文件发呆,果断Get到gcd(f[i], f[j]) = f[gcd(i,j)],看一下数据范围,模数很小不需要高精,直接矩阵快速幂求f[..],本题100分。(某个神奇的eirlys同学迅速发现规律然而不会打矩阵快速幂2333)
1. 我们先来看看几个有关fibonacci的引理。 有点难以理解,反正这套题难度是递减的。。。 引理1: Gcd(F[n+1],F[n])=1; 证明: 根据辗转相减法则 Gcd(F[n+1],F[n])=Gcd(F[n+1]-F[n],F[n]) =Gcd(F[n],F[n-1]) =Gcd(F[2],F[1]) =1 引理2: F[m+n]=F[m-1]F[n]+F[m]F[n+1] 证明: F[n+m]=F[n+m-1]+F[n+m-2] =2*F[n+m-2]+F[n+m-3] =…… F[n+m]=a[x]*F[n+m-x]+b[x]*F[n+m-x-1]; =a[x]*(F[n+m-x-1]+F[n+m-x-2])+b[x]*(F[n+m-x-1); =(a[x]+b[x])*F[n+m+x-1]+a[x]*F[n+m+x-2]; 当x=1时有 a[1]=F[2]; b[1]=F[1]; 当x=2时有 a[2]=F[2]+F[1]=F[3]; b[2]=a[1]=F[2]; 当x=k+1时有 a[k+1]=a[k]+b[k]=F[k+1]+F[k]=F[k+2] b[k+1]=a[k]=F[k+1]; 所以当x=n时 F[n+m]=a[n]F[m]+b[n]F[m-1]; =F[n+1]F[m]+F[n]F[m-1]; 引理3: Gcd(F[n+m],F[n])=Gcd(F[n],F[m]) 证明: Gcd(F[n+m],F[n]) =Gcd(F[n+1]F[m]+F[n]F[m-1],F[n]); =Gcd(F[n+1]F[m],F[n]); =Gcd(F[n+1],F[n])*Gcd(F[m],F[n]) =Gcd(F[m],F[n]); 由以上三个引理有:Gcd(F[n],F[m])=F[Gcd(n,m)];
以上为证明,反正本菜是没有能力证明,,
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 const int mod = 19491001; 6 int n; 7 int tx, ty; 8 9 struct data { 10 long long x1, x2, x3, x4; 11 data (long long x1 = 1, long long x2 = 0, long long x3 = 0, long long x4 = 1) : x1(x1), x2(x2), x3(x3), x4(x4) {}; 12 }; 13 14 int gcd(int a, int b) { 15 if (b == 0) return a; 16 return (gcd(b, a % b)); 17 } 18 19 data operator * (data a, data b) { 20 data c; 21 c.x1 = (a.x1 * b.x1 + a.x2 * b.x3) % mod; 22 c.x2 = (a.x1 * b.x2 + a.x2 * b.x4) % mod; 23 c.x3 = (a.x3 * b.x1 + a.x4 * b.x3) % mod; 24 c.x4 = (a.x3 * b.x2 + a.x4 * b.x4) % mod; 25 return (c); 26 } 27 28 data qpow(data x, int v) { 29 data ans; 30 while (v > 0) { 31 if (v & 1) ans = ans * x; 32 x = x * x; 33 v >>= 1; 34 } 35 return (ans); 36 } 37 38 int main () { 39 freopen("fibonacci.in", "r", stdin); 40 freopen("fibonacci.out", "w", stdout); 41 scanf("%d", &n); 42 for (int i = 1; i <= n; i++) { 43 scanf("%d %d", &tx, &ty); 44 int ans = gcd(tx, ty); 45 data cur(0, 1, 1, 1); 46 cur = qpow(cur, ans-2); 47 long long tans = ((cur.x2 + cur.x4) % mod + mod) % mod; 48 printf("%I64d ", tans); 49 } 50 51 return 0; 52 }
第一题代码略丑,矩阵乘法一直写得不好看,见谅。
3、题目描述还算清楚,只是思考黄金分割数取多少时纠结了一下,后来发现取0.618在n较大时毫无意义,开始按照带根号的那个东西来做,第一感觉O(nlog(n))枚举加二分求解,依旧开始打表,偶然发现这些数字有点熟悉,,,好吧又是斐波拉契数,,发现对于一个数n,它的最接近黄金分割数的值为 小于等于它的两个斐波拉契数作比,问题至此圆满解决,,至于证明,,自行百度吧,,
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 unsigned long long f[100]; 6 unsigned long long n; 7 8 int main () { 9 freopen("gold.in", "r", stdin); 10 freopen("gold.out", "w", stdout); 11 f[1] = 1; 12 f[2] = 1; 13 for (int i = 3; i <= 93; i++) f[i] = f[i-1] + f[i-2]; 14 f[94] = 0 - 1; 15 //for (int i = 1; i <= 94; i++) printf("%I64u ", f[i]); 16 scanf("%I64u", &n); 17 for (int i = 2; i <= 93; i++) { 18 if (f[i] <= n && f[i+1] > n) { 19 printf("%I64u/%I64u", f[i-1], f[i]); 20 } 21 } 22 return 0; 23 }
4、考试时打的暴力,还打丑了,,一下子就被zgc拉开了50分,,,-_-,标答如下:首先枚举每一个号码,将它按照题目中所给的允许变化的方案进行变化,将变化结果存在hashtable里,之后利用hash进行判重,如果出现变化后的值与变化前的相同,对两个点进行暴力lcp并连边,最后spfa求解
代码嘛,,,还没写完= =。。
2、考试时没看懂题目,,考完后感觉题目描述有问题,总体感觉这题目并不是很可做,,先粘一个题解吧,以后再完善
1 稍加思索可以发现,行列之间是互不影响的,把每行1的个数看做n堆纸牌、每列1的个数 2 看做m堆纸牌,题目实际上就是两个环形的均分纸牌问题。 3 下面来说环形均分纸牌问题怎么做: 4 设有n堆纸牌,每堆有ai张,所有堆一共有S张,那么最终每堆应该有Sn张。因此如果s mod ai≠0,显然是无解的。接下来构造数列bi=ai-sn。 5 方法一: 6 枚举从第k个位置开始(1=k=n),像均分纸牌的方法一样依次向后推(如果第i 个位置有ai堆牌,那么取bi堆牌分给下一堆,若bi0表示从下一堆拿到这一堆)。最后取最小值。 7 时间复杂度O(n^2),预计得分70分。 8 方法二: 9 设bi的前缀和为si。如果从第k个位置开始,那么第i堆和第i+1堆交换的纸牌数就是 si-sk。总代价就是s1-sk+s2-sk+s3-sk+……+sn-sk。发现什么了?当sk是s1~sn中位数的时候, 10 上式有最小值!所以把si排序后,令sk=s[(n+1)2],计算代价即可。 11 时间复杂度O(nlogn),预计得分100分。