zoukankan      html  css  js  c++  java
  • EOJ 1031 传球问题

    EOJ 1031 http://acm.cs.ecnu.edu.cn/problem.php?problemid=1031

    题意:

      传球问题,按题意我们得到编号从1~2~..~ i ~..~n~1的,那么去掉末尾的1(将环从n后剪开),

      我们得到:1~2~..~ i ~..~n,多了首尾不同的限制,于是问题完全等价 HDU 2045 —— 染色问题(做过这题的话,很容易想到)。

      HDU 2045  http://acm.hdu.edu.cn/showproblem.php?pid=2045

      具体分析:

      n为传球总次数,i 一个空位, 待填入接到第 i-1 次传球的人;

      又有p个人,记为x1,x2...,xp;按题意:编号1处只有一种选择,不妨填x1,而2~n可以有多种填法, 但须有相邻(包括首尾)的不同。

      以下用填格子指代传球。

      记f[n]为填到第 n 个格子时的总填法。那么分为两种:(n>=3)

      按照  第n-1个格子与首位  的关系;

      1.相同:第n-1个格子——1种填法=>第n个格子——p-1种;剩下前n-2个格子为子问题f[n-2]。

      2.不同:第n-1个格子——p-1种填法=>第n个格子——p-2种;

          (由于第n-1个格子与首位不同)这时,前n-1个格子本身即为子问题f[n-1]。

      这样容易写出递推关系:

      f[n] = (p-1)*f[n-2] + (p-2)*f[n-1];   

      题意要求结果对2005取模:那么只需:

      f[n] = ( ((p-1)%M) * f[n-2]  + ((p-2)%M) * f[n-1] )%M;  //M为2005

      此题的另一个要注意的是:n, p 都很大,不能暴力求解。  

      注意到 f[n] = (p-1)*f[n-2] + (p-2)*f[n-1]; <=>  f[n] = A*x^n + B*y^n; (A,B,x,y∈N)。

      由抽屉原理:设a[n] = (A*x^n)%M; M为某常数, 则a[n]一定循环(n>M 时),循环节最大为M;

      B*y^n同理, 所以f[n]循环节最大为M^2;

      代码如下:

      

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string>
     4 #include <algorithm>
     5 #include <string.h>
     6 #include <stdlib.h>
     7 #define INF 0x3f3f3f 
     8 #define MAX 2010
     9 #define M 2005
    10 using namespace std;
    11 short f[MAX*MAX];
    12 void print(int *f)
    13 {
    14     for(int i=1; i<=10; i++)
    15         cout << i << ". " << f[i] << endl;
    16 }
    17 int main()
    18 {
    19     //freopen("testin.txt", "r", stdin);
    20     //freopen("testout.txt", "w", stdout);
    21     
    22     int p, n;
    23     while(cin >> p >> n, p&&n)
    24     {
    25         int i;
    26         f[1] = 0;
    27         f[2] = (p-1)%M;
    28         for(i=3; i<=n; i++)
    29         {            
    30             f[i] = (((p-1)%M)*f[i-2] + ((p-2)%M)*f[i-1])%M;
    31             if(f[i-1] == f[1] && f[i] == f[2])
    32                 break;    //当循环时即可跳出。 
    33         }
    34         //print(f);
    35         if(i<n)        //循环 
    36         {
    37             int loop = i-2; 
    38             int ans = n%loop;
    39             if(n%loop == 0)
    40                 ans = loop;
    41             cout << f[ans] << endl;
    42         }
    43         else    //n较小,未循环  
    44             cout << f[n] << endl;
    45     } 
    46     
    47     
    48     return 0;
    49 }
    View Code

      

  • 相关阅读:
    关于表单的练习和基本登录界面的制作
    css3 闪光hover
    步步为营:Asp.Net序列化与反序列化
    步步为营:Asp.Net客户端存Cookie服务端取
    步步为营:Asp.Net使用HttpWebRequest通知,抓取,采集
    PHP学习(二):PHP的魔术方法
    步步为营:SQL通用存储过程分页
    PHP学习(三):PHP面向对象概念
    PHP学习(四):PHP5.3版本的新特性
    步步为营:Asp.Net转换Unix时间戳
  • 原文地址:https://www.cnblogs.com/KimKyeYu/p/3132930.html
Copyright © 2011-2022 走看看