博文

Zoj 1222 Just the Facts(2007-03-02 22:54:00)

摘要:这是标准的数学题。求N!的非零末位。 这也是标准的BT题,光是N就可以到100位。完全没有直接做的办法。还是看LeeMars的报告吧! 首先考虑某一个N!(N < 10),我们先将所有5的倍数提出来,用1代替原来5的倍数的位置。由于5的倍数全被提走了,所以这样就不会出现尾数0了。我们先把0..9的阶乘的尾数列出来(注意,5的倍数的位置上是1),可以得到table[0..9] = (1, 1, 2, 6, 4, 4, 4, 8, 4, 6)。对于N < 5,直接输出table[N]即可;对于N > = 5,由于提出了一个5,因此需要一个2与之配成10,即将尾数除以2。注意到除了0 !和1!,阶乘的最后一个非零数字必为偶数(显然,因为在N!的质因数里2的个数要多),所以有一个很特别的除法规律:2 / 2 = 6,4 / 2 = 2,6 / 2 = 8,8 / 2 = 4。比较特殊的就是2 / 2 = 12 / 2 = 6, 6 / 2 = 16 / 2 = 8。这样我们就可以得到如下式子: 代码:           table[N] F(N) = ------------ (0 <= N < 10)           2^([N/5]) 再考虑复杂的。考虑某一个N!(N >= 10),我们先将所有5的倍数提出来,用1代替原来5的倍数的位置。由于5的倍数全被提走了,所以这样就不会出现尾数0了。我们观察一下剩下的数的乘积的尾数,通过table表,我们发现这10个数的乘积的尾数是6,6 * 6的尾数还是6,因此我们将剩下的数每10个分成一组,则剩下的数的乘积的尾数只与最后一组的情况有关,即与N的最后一位数字有关。由于我们把5的倍数提出来了,N!中一次可以提出[N/5]个5的倍数,有多少个5,就需要有多少个2与之配成10,所以有多少个5,最后就要除以多少个2。注意到除2的结果变化是4个一循环,因此如果有A个5,只需要除(A MOD 4)次2就可以了。A MOD 4只与A的最后两位数有关,很好求算。剩......

阅读全文(5871) | 评论:2

Zju 2759 Perfect Weighing Skill Ⅱ(2006-10-01 22:31:00)

摘要: 2087262 2006-10-01 22:05:43 Accepted 2759 C++ 00:00.10 392K Sirius.D     这题原来如此简单````根本用不到搜索,更谈不上剪枝..可在那时,却害的我肝肠寸断,为伊消得人憔悴.....可叹一位如花似玉的少年,就这样被zoj的Monthly吓的花容失色,颤抖抖,惊颤颤...     (正色道)此题(参见前文)只需把数改成三进制,不断的「借位」进位即可.     如6,即为2,0 == 1,-1,0;     35,即是1,0,2,2 == 1,1,0,-1;     如此这般,这般如此,1处取加,-1处取减,可爱的ac就在你的眼前. #include <cstdio>#include <string> int b[19], n, l; void pt(){ int af = 0, bf = 0, i, x = 1; for(i = 0; i <= l; i ++) {  if(b[i] == -1)  {   af = 1;   if(bf)    printf(" ");   printf("%d", x);   bf = 1;  }  x *= 3; } if(!af)  printf("-1"); printf("\n"); af = 0, bf = 0, x = 1; for(i = 0; i <= l; i ++) {  if(b[i] == 1)  {   af = 1;   if(bf)  ......

阅读全文(4123) | 评论:1

Zju 1084 Channel Allocation(2006-08-29 20:12:00)

摘要:顶点着色的贪婪算法证明是存在的,即当前的算法得到只是给出最少颜色的一个上界。 算法描述:设G是一个图,它的顶点按某一顺序记为x1,x2,......xn. (1) 对顶点x1指定颜色1。 (2)对每个i=2,3,....n,令p是在顶点x1,x2,...xi-1与xi相邻接的顶点中没有任何一个顶点着色p的最小的颜色,并且xi指定颜色p。 数学书上的定理为:设G是一个图,对于该图顶点的最大度为△,那么贪婪算法X产生G的顶点的一个(△+1)着色,因此 X(G)<=△+1 #include <cstdio>#include <string> int a[26][26], n, m, ans, c[26], b[26];char s[26]; void greedy(){ int i, k; for(i = 0; i < n; i ++) {  memset(b, 0, sizeof(b));  for(k = 0; k < n; k ++)  {   if(a[i][k] && c[k] != -1)   {    b[c[k]] = 1;   }  }  for(k = 0; k <= i; k ++)  {   if(!b[k]) break;  }  c[i] = k; } for(i = 0; i < n; i ++) {  if(ans < c[i])   ans = c[i]; } ans ++;} void init(){ memset(a, 0, sizeof(a)); for(int i = 0; i < n; i ++) {  c[i] = -1; }&n......

阅读全文(4148) | 评论:2

Zju 1619 Present(2006-08-08 22:40:00)

摘要: 2009974 2006-08-08 22:21:50 Accepted 1619 C++ 00:00.02 392K St.Crux 首先要知道什么是错排。 清楚了以后这个题就是弱题。即求: C(n,m)——n个数里取m个的组合数 × 剩下的(n-m)个数的错排数 注意n==m的情况 #include <cstdio> int m, n; double a[101]; int main(){ //freopen("in.txt", "r", stdin); a[1] = 0, a[2] = 1; int i; for(i = 3; i < 101; i ++) {  a[i] = (i - 1) * (a[i - 1] + a[i - 2]); } while(scanf("%d %d", &n, &m) != EOF) {  double pb = 1;  if(n == m)  {   //pb *= a[n];   for(i = 1; i <= n; i ++)   {    pb /= double(i);   }  }  else  {   pb *= a[n - m];   for(i = 1; i <= m; i ++)   {    pb /= double(i);   }   for(i = 1; i <= n - m; i ++)   {    pb /= double(i);   }&nbs......

阅读全文(3539) | 评论:0