1. 程式人生 > >演算法-藍橋杯習題(5-2)

演算法-藍橋杯習題(5-2)

藍橋杯習題

藍橋杯練習系統習題加答案,總共分為6部分,90%習題使用C語言解答,部分使用C++或者Java。大部分習題為搜尋參考或者別人提供所得,不足之處在所難免,懇請批評指正(預計200多題,習題僅供學習交流)

目錄

藍橋杯練習系統評測資料

歷屆試題(PartC-14題)

密碼: a933

歷屆試題(PartC-14題)


/*
歷屆試題 迴文數字

問題描述
  觀察數字:12321,123321 都有一個共同的特徵,無論從左到右讀還是從右向左讀,都是相同的。這樣的數字叫做:迴文數字。

  本題要求你找到一些5位或6位的十進位制數字。滿足如下要求:
  該數字的各個數位之和等於輸入的整數。
輸入格式
  一個正整數 n (10<n<100), 表示要求滿足的數位和。
輸出格式
  若干行,每行包含一個滿足要求的5位或6位整數。
  數字按從小到大的順序排列。
  如果沒有滿足條件的,輸出:-1
樣例輸入
44
樣例輸出
99899
499994
589985
598895
679976
688886
697796
769967
778877
787787
796697
859958
868868
877778
886688
895598
949949
958859
967769
976679
985589
994499
樣例輸入
60
樣例輸出
-1
*/

#include<stdio.h>
int main()
{
    int a,b,c;
    int n;
    int flag=-1;
    scanf("%d",&n);
    
    for(a=1;a<10;a++)
    {
        for(b=0;b<10;b++)
        {
            for(c=0;c<10;c++)
            {
                if(a+b+c+b+a==n)
                {
                    flag=1;
                    printf("%d%d%d%d%d\n",a,b,c,b,a);
                }
            }
        }
    }

    for(a=1;a<10;a++)
    {
        for(b=0;b<10;b++)
        {
            for(c=0;c<10;c++)
            {
                if(a+b+c+c+b+a==n)
                {
                    printf("%d%d%d%d%d%d\n",a,b,c,c,b,a);
                    flag=1;
                }
            }
        }
    }
    if(flag==-1)
        printf("%d\n",flag);
    return 0;
}

/*
歷屆試題 國王的煩惱

問題描述
  C國由n個小島組成,為了方便小島之間聯絡,C國在小島間建立了m座大橋,每座大橋連線兩座小島。兩個小島間可能存在多座橋連線。然而,由於海水沖刷,有一些大橋面臨著不能使用的危險。

  如果兩個小島間的所有大橋都不能使用,則這兩座小島就不能直接到達了。然而,只要這兩座小島的居民能通過其他的橋或者其他的小島互相到達,他們就會安然無事。但是,如果前一天兩個小島之間還有方法可以到達,後一天卻不能到達了,居民們就會一起抗議。

  現在C國的國王已經知道了每座橋能使用的天數,超過這個天數就不能使用了。現在他想知道居民們會有多少天進行抗議。
輸入格式
  輸入的第一行包含兩個整數n, m,分別表示小島的個數和橋的數量。
  接下來m行,每行三個整數a, b, t,分別表示該座橋連線a號和b號兩個小島,能使用t天。小島的編號從1開始遞增。
輸出格式
  輸出一個整數,表示居民們會抗議的天數。
樣例輸入
4 4
1 2 2
1 3 2
2 3 1
3 4 3
樣例輸出
2
樣例說明
  第一天後2和3之間的橋不能使用,不影響。
  第二天後1和2之間,以及1和3之間的橋不能使用,居民們會抗議。
  第三天後3和4之間的橋不能使用,居民們會抗議。
資料規模和約定
  對於30%的資料,1<=n<=20,1<=m<=100;
  對於50%的資料,1<=n<=500,1<=m<=10000;
  對於100%的資料,1<=n<=10000,1<=m<=100000,1<=a, b<=n, 1<=t<=100000。
*/
#include<stdio.h>
#include<malloc.h>
int a[100001],b[100001],c[100001],d[10001];
struct tubiao
{
    int n;
    struct tubiao *next;
}tu[10001];
void add(int u,int v)
{
    struct tubiao *p=(struct tubiao*) malloc(sizeof(struct tubiao));
    p->n=v;
    p->next=NULL;
    struct tubiao *q=&tu[u];
    while(q->next)
       {  q=q->next;
          
       }
    q->next=p;
}
void paixu(int first,int last)
{  if(first<last)
     {
          int i=first,j=last,ka=a[first],kb=b[first],kc=c[first];
          while(i<j)
          {
              while(i<j&&kc<=c[j])
                  j--;
              a[i]=a[j];b[i]=b[j];c[i]=c[j];
              while(i<j&&kc>=c[i])
                  i++;
             a[j]=a[i];b[j]=b[i];c[j]=c[i];
             
         }
         a[i]=ka;b[i]=kb;c[i]=kc;
         paixu(first,i-1);
         paixu(i+1,last);
     }
    
}
int f1(int i)
{
    if(d[i]==i)
      return i;
    int u=f1(d[i]);
    d[i]=u;
    return d[i];
}
int main()
{
    int n,m,i1,u,v,t,i2;
    scanf("%d%d",&n,&m);
    for(i1=0;i1<m;i1++)
    {   scanf("%d%d%d",&u,&v,&t);
        a[i1]=u;b[i1]=v;c[i1]=t;
        add(u,v);
        add(v,u);
    }
    paixu(0,m-1);
    int  total=0,tianshu=0;
 for(i1=1;i1<=n;i1++)
    d[i1]=i1;
 for(i1=m-1;i1>=0;i1--)
 {     int ko=f1(a[i1]);
       int ok=f1(b[i1]);
      if(ko==ok)
          {
             continue;    
          }
      else 
         {
             d[ko]=b[i1];
             if(tianshu!=c[i1])
                {
                     total++;
                     tianshu=c[i1];
                   }
                
         }
 }
  printf("%d\n",total);
    return 0;
}

/*
歷屆試題 數字遊戲

問題描述
  棟棟正在和同學們玩一個數字遊戲。

  遊戲的規則是這樣的:棟棟和同學們一共n個人圍坐在一圈。棟棟首先說出數字1。接下來,坐在棟棟左手邊的同學要說下一個數字2。再下面的一個同學要從上一個同學說的數字往下數兩個數說出來,也就是說4。下一個同學要往下數三個數,說7。依次類推。

  為了使數字不至於太大,棟棟和同學們約定,當在心中數到 k-1 時,下一個數字從0開始數。例如,當k=13時,棟棟和同學們報出的前幾個數依次為:
  1, 2, 4, 7, 11, 3, 9, 3, 11, 7。

  遊戲進行了一會兒,棟棟想知道,到目前為止,他所有說出的數字的總和是多少。
輸入格式
  輸入的第一行包含三個整數 n,k,T,其中 n 和 k 的意義如上面所述,T 表示到目前為止棟棟一共說出的數字個數。
輸出格式
  輸出一行,包含一個整數,表示棟棟說出所有數的和。
樣例輸入
3 13 3
樣例輸出
17
樣例說明
  棟棟說出的數依次為1, 7, 9,和為17。
資料規模和約定
  1 < n,k,T < 1,000,000;
*/
#include <stdio.h>
#include <windows.h>3 
int s[1000000];
// 3  13  9 
//  1 2 4 7 11 3 9 3 11 7 4 2 1    1 2 4 7 11 3 9 3 11 7 4 2 1 
int main()
{
long long n,k,t,i,j=1,g=1,z,sum=0;
scanf("%I64d%I64d%I64d",&n,&k,&t);
if(k%2==0) z=k*2;
else z=k;
s[0]=1;
do    //開始製表 
{
j+=g;
if(j>=k) j%=k; 
s[g]=j;
g++;     
}                         
while(g<=z) ; 
k=0;      
for(i=0;i<t;i++)
{
 sum+=s[k];
 k+=n;
 if(k>g-1) k-=g-1;             
}                 

                
printf("%I64d",sum);
system("pause");
 return 0;   
}

/*
歷屆試題 郵局

問題描述
  C村住著n戶村民,由於交通閉塞,C村的村民只能通過信件與外界交流。為了方便村民們發信,C村打算在C村建設k個郵局,這樣每戶村民可以去離自己家最近的郵局發信。

  現在給出了m個備選的郵局,請從中選出k個來,使得村民到自己家最近的郵局的距離和最小。其中兩點之間的距離定義為兩點之間的直線距離。
輸入格式
  輸入的第一行包含三個整數n, m, k,分別表示村民的戶數、備選的郵局數和要建的郵局數。
  接下來n行,每行兩個整數x, y,依次表示每戶村民家的座標。
  接下來m行,每行包含兩個整數x, y,依次表示每個備選郵局的座標。
  在輸入中,村民和村民、村民和郵局、郵局和郵局的座標可能相同,但你應把它們看成不同的村民或郵局。
輸出格式
  輸出一行,包含k個整數,從小到大依次表示你選擇的備選郵局編號。(備選郵局按輸入順序由1到m編號)
樣例輸入
5 4 2
0 0
2 0
3 1
3 3
1 1
0 1
1 0
2 1
3 2
樣例輸出
2 4
資料規模和約定
  對於30%的資料,1<=n<=10,1<=m<=10,1<=k<=5;
  對於60%的資料,1<=m<=20;
  對於100%的資料,1<=n<=50,1<=m<=25,1<=k<=10。
*/
#include <stdio.h>
#include <math.h>

using namespace std;

struct Point {
    int no;
    int x, y;

    double getDist(Point p) {
        return sqrt((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y));
    }
};

Point ans[10];
int n, m, k;
Point person[50];
Point fire[25];
Point result[10];
bool repeat[50], ban[50];
double ansDist = 1000000000;
double minDist[50], sum = 0;
double G[50][25];

void dfs(int deep, int index)
{
    if(deep == k) {
        if(sum < ansDist) {
            ansDist = sum;
            for(int i = 0; i < k; i++) {
                ans[i] = result[i];
            }
        }
    } else {
        double tmpDist[50] = {0}, tsum = sum;
        bool flag2 = false;
        for(int i = 0; i < n; i++)
            tmpDist[i] = minDist[i];
        for(int i = m-k+deep; i >= index; i--) {
            if(repeat[i]) continue;
            if(deep > 0 && ban[i]) continue;
            bool flag = false;
            if(deep == 0) {
                sum = 0;
                for(int j = 0; j < n; j++) {
                    minDist[j] = G[j][i];
                    sum += G[j][i];
                }
                flag = true;
            }
            else {
                sum = tsum;
                for(int j = 0; j < n; j++) {
                    if(G[j][i] < tmpDist[j]) {
                        sum -= tmpDist[j] - G[j][i];
                        minDist[j] = G[j][i];
                        flag = true;
                    } else minDist[j] = tmpDist[j];
                }
            }
            if(flag) {
                flag2 = true;
                result[deep] = fire[i];
                dfs(deep+1, result[deep].no + 1);
            } else {
                ban[i] = true;
            }
        }
        if(flag2 == false) {
            result[deep] = fire[result[deep-1].no+1];
            dfs(deep+1, m-k+deep+1);
        } else {
            sum = tsum;
            for(int j = 0; j < n; j++) {
                minDist[j] = tmpDist[j];
            }
        }
    }
}

int main()
{
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 0; i < n; i++) {
        scanf("%d%d", &person[i].x, &person[i].y);
        minDist[i] = ansDist;
    }
    for(int i = 0; i < m; i++) {
        scanf("%d%d", &fire[i].x, &fire[i].y);
        fire[i].no = i;
    }
    for(int i = 0; i < m; i++) {
        if(!repeat[i]) {
            for(int j = i+1; j < m; j++)
                if(fire[i].x == fire[j].x && fire[i].y == fire[j].y)
                    repeat[j] = true;
        }
    }
    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++)
            G[i][j] = person[i].getDist(fire[j]);
    dfs(0, 0);
    for(int i = 0; i < k; i++) {
        printf("%d ", ans[i].no+1);
    }
    return 0;
}

/*
歷屆試題 城市建設

問題描述
  棟棟居住在一個繁華的C市中,然而,這個城市的道路大都年久失修。市長準備重新修一些路以方便市民,於是找到了棟棟,希望棟棟能幫助他。

  C市中有n個比較重要的地點,市長希望這些地點重點被考慮。現在可以修一些道路來連線其中的一些地點,每條道路可以連線其中的兩個地點。另外由於C市有一條河從中穿過,也可以在其中的一些地點建設碼頭,所有建了碼頭的地點可以通過河道連線。

  棟棟拿到了允許建設的道路的資訊,包括每條可以建設的道路的花費,以及哪些地點可以建設碼頭和建設碼頭的花費。

  市長希望棟棟給出一個方案,使得任意兩個地點能只通過新修的路或者河道互達,同時花費盡量小。
輸入格式
  輸入的第一行包含兩個整數n, m,分別表示C市中重要地點的個數和可以建設的道路條數。所有地點從1到n依次編號。
  接下來m行,每行三個整數a, b, c,表示可以建設一條從地點a到地點b的道路,花費為c。若c為正,表示建設是花錢的,如果c為負,則表示建設了道路後還可以賺錢(比如建設收費道路)。
  接下來一行,包含n個整數w_1, w_2, …, w_n。如果w_i為正數,則表示在地點i建設碼頭的花費,如果w_i為-1,則表示地點i無法建設碼頭。
  輸入保證至少存在一個方法使得任意兩個地點能只通過新修的路或者河道互達。
輸出格式
  輸出一行,包含一個整數,表示使得所有地點通過新修道路或者碼頭連線的最小花費。如果滿足條件的情況下還能賺錢,那麼你應該輸出一個負數。
樣例輸入
5 5
1 2 4
1 3 -1
2 3 3
2 4 5
4 5 10
-1 10 10 1 1
樣例輸出
9
樣例說明
  建設第2、3、4條道路,在地點4、5建設碼頭,總的花費為9。
資料規模和約定
  對於20%的資料,1<=n<=10,1<=m<=20,0<=c<=20,w_i<=20;
  對於50%的資料,1<=n<=100,1<=m<=1000,-50<=c<=50,w_i<=50;
  對於70%的資料,1<=n<=1000;
  對於100%的資料,1 <= n <= 10000,1 <= m <= 100000,-1000<=c<=1000,-1<=w_i<=1000,w_i≠0。
*/
#include<cstdio>
#include<algorithm>
using namespace std;
const int NO=100006;
const int INF=1000000000;
struct R
{
    int a,b,w;
}r[NO*10];
int fa[NO];
int n,m,sum;
void reset_fa()
{
    for(int i=0;i<=n;i++)
        fa[i]=i;
}
bool comp(const R &a,const R &b){return a.w<b.w;}
int find(int k){return k==fa[k]?k:fa[k]=find(fa[k]);}
int kruskal()
{
    int i,num=0,a,b,k;
    for(i=1;i<=m;i++)
    {
        a=find(r[i].a);
        b=find(r[i].b);
        if(a!=b)
        {
            if(r[i].a==0)
            {
                num++;
                k=r[i].w;
            }
            sum+=r[i].w;
            fa[a]=b;
        }
    }
    if(num==1)
    {
        sum-=k;
    }
    return sum;
}
int main()
{
    int i=1,j,a,b;
    scanf("%d%d",&n,&m);
    reset_fa();
    while(m--)
    {
        scanf("%d%d%d",&r[i].a,&r[i].b,&r[i].w);
        if(r[i].w<0)
        {
            sum+=r[i].w;
            a=find(r[i].a);
            b=find(r[i].b);
            if(a!=b)
                fa[a]=b;
        }
        else
            i++;
    }
    for(j=1;j<=n;j++)
    {
        scanf("%d",&a);
        if(a!=-1)
        {
            r[++i].a=0;
            r[i].b=j;
            r[i].w=a;
        }
    }
    m=i;
    sort(r+1,r+1+m,comp);
    printf("%d\n",kruskal());
    return 0;
}

/*
歷屆試題 最大子陣

問題描述
  給定一個n*m的矩陣A,求A中的一個非空子矩陣,使這個子矩陣中的元素和最大。

  其中,A的子矩陣指在A中行和列均連續的一塊。
輸入格式
  輸入的第一行包含兩個整數n, m,分別表示矩陣A的行數和列數。
  接下來n行,每行m個整數,表示矩陣A。
輸出格式
  輸出一行,包含一個整數,表示A中最大的子矩陣中的元素和。
樣例輸入
3
-1 -4 3
4 -1
-5 -2 8
樣例輸出
樣例說明
  取最後一列,和為10。
資料規模和約定
  對於50%的資料,1<=n, m<=50;
  對於100%的資料,1<=n, m<=500,A中每個元素的絕對值不超過5000。
*/
#include "stdio.h"
#include "string.h"
int a[500][500],b[500];
int f(int n,int m)
{int i,j,k,t,max=-999999;
for(i=0;i<n;i++)
  {memset(b,0,m*sizeof(int));
   
    for(j=i;j<n;j++)
    {t=-999999;
    for(k=0;k<m;k++)
     {b[k]+=a[j][k];
       t+=b[k];
       if(t<b[k])t=b[k];
       if(max<t)max=t;    
     }    
    }
    
    
  }
  return max;
}
int main()
{
    int i,j,n,m;
    scanf("%d%d",&n,&m);
    for(i=0;i<n;i++)
    for(j=0;j<m;j++)
    scanf("%d",&a[i][j]);
    
    printf("%d",f(n,m));

    return 0;
}

/*
歷屆試題 螞蟻感冒

問題描述
  長100釐米的細長直杆子上有n只螞蟻。它們的頭有的朝左,有的朝右。

  每隻螞蟻都只能沿著杆子向前爬,速度是1釐米/秒。

  當兩隻螞蟻碰面時,它們會同時掉頭往相反的方向爬行。

  這些螞蟻中,有1只螞蟻感冒了。並且在和其它螞蟻碰面時,會把感冒傳染給碰到的螞蟻。

  請你計算,當所有螞蟻都爬離杆子時,有多少隻螞蟻患上了感冒。
輸入格式
  第一行輸入一個整數n (1 < n < 50), 表示螞蟻的總數。

  接著的一行是n個用空格分開的整數 Xi (-100 < Xi < 100), Xi的絕對值,表示螞蟻離開杆子左邊端點的距離。正值表示頭朝右,負值表示頭朝左,資料中不會出現0值,也不會出現兩隻螞蟻佔用同一位置。其中,第一個資料代表的螞蟻感冒了。
輸出格式
  要求輸出1個整數,表示最後感冒螞蟻的數目。
樣例輸入
3
5 -2 8
樣例輸出
1
樣例輸入
5
-10 8 -20 12 25
樣例輸出
3
*/
#include <stdio.h>
struct mayi
{
    int direct;  //0為左,1為右 
    int dist;   //距離左端點距離 
    int cold;  //0為正常,1為感冒     
} ;

int main()
{
int n,i,sign,j,num=0;
scanf("%d",&n);
struct mayi a[n];
for(i=0;i<n;i++)
{
scanf("%d",&a[i].dist);
a[i].dist*=2;
a[i].direct=1;
a[i].cold=0;
if(a[i].dist<0) 
{
    a[i].dist*=-1;
    a[i].direct=0;    
}    
a[0].cold=1;    
} 
    
    for(;;)
   {
       sign=0;
         for(i=0;i<n;i++)  //所有螞蟻走路 
           {
               if(a[i].direct==0) a[i].dist--;
               else a[i].dist++;
           } 
   
           for(i=0;i<n-1;i++)
          for(j=i+1;j<n;j++)
           {
        if(a[i].dist==a[j].dist)
        {
            if(a[i].direct==0) 
            {a[i].direct=1;    }
            else a[i].direct=0;
            
            if(a[j].direct==0)
            { a[j].direct=1;}
            else a[j].direct=0;
            
            if(a[i].cold==1 ) a[j].cold=1; 
            
            if(a[j].cold==1 ) a[i].cold=1; 
            
          }
        }
   
       for(i=0;i<n;i++)
      {
         if(a[i].dist>=0 && a[i].dist<=200)
          {
           sign=1;
           break;
           
         }
        
       }
   
        if(sign==0) break;
   
  }
    for(i=0;i<n;i++)
    {
        
        if(a[i].cold==1) num++;
    }

    printf("%d\n",num);

    return 0;
}

/*
歷屆試題 地宮取寶

問題描述
  X 國王有一個地宮寶庫。是 n x m 個格子的矩陣。每個格子放一件寶貝。每個寶貝貼著價值標籤。

  地宮的入口在左上角,出口在右下角。

  小明被帶到地宮的入口,國王要求他只能向右或向下行走。

  走過某個格子時,如果那個格子中的寶貝價值比小明手中任意寶貝價值都大,小明就可以拿起它(當然,也可以不拿)。

  當小明走到出口時,如果他手中的寶貝恰好是k件,則這些寶貝就可以送給小明。

  請你幫小明算一算,在給定的局面下,他有多少種不同的行動方案能獲得這k件寶貝。
輸入格式
  輸入一行3個整數,用空格分開:n m k (1<=n,m<=50, 1<=k<=12)

  接下來有 n 行資料,每行有 m 個整數 Ci (0<=Ci<=12)代表這個格子上的寶物的價值
輸出格式
  要求輸出一個整數,表示正好取k個寶貝的行動方案數。該數字可能很大,輸出它對 1000000007 取模的結果。
樣例輸入
2 2 2
1 2
2 1
樣例輸出
2
樣例輸入
2 3 2
1 2 3
2 1 5
樣例輸出
14
*/
#include<stdio.h>
#include<string.h>

#define N 55
#define MOD  1000000007

int map[55][55];
int dp[55][55][15][15];

int main(void)
{
    int n, m, k;
    int i, j, c, val, aMax;
    scanf("%d%d%d", &n, &m, &k);
    aMax = 0;
    for(i = 1; i <= n; i++)
    {
        for(j = 1; j <= m; j++)
        {
            scanf("%d", &map[i][j]);
//            map[i][j]++;
            if(aMax < map[i][j])
            {
                aMax = map[i][j];
            }
        }
    }
    memset(dp, 0, sizeof(dp));
    dp[1][1][0][0] = 1;
    dp[1][1][1][map[1][1]] = 1;
    for(i = 1; i <= n; i++)
    {
        for(j = 1; j <= m; j++)
        {
            dp[i][j][0][0] += dp[i][j - 1][0][0] + dp[i - 1][j][0][0];
            dp[i][j][0][0] %= MOD;
            for(c = 1; c <= k; c++)
            {
                for(val = 0; val <= aMax; val++)
                {
                    dp[i][j][c][val] += dp[i][j - 1][c][val] + dp[i - 1][j][c][val];
                    dp[i][j][c][val] %= MOD;
                }
                if(c == 1)
                {
                    dp[i][j][1][map[i][j]] += dp[i][j - 1][0][0];
                    dp[i][j][1][map[i][j]] %= MOD;
                    dp[i][j][1][map[i][j]] += dp[i - 1][j][0][0];
                    dp[i][j][1][map[i][j]] %= MOD;
                }
                else
                {
                    for(val = 0; val < map[i][j]; val++)
                    {
                        dp[i][j][c][map[i][j]] += dp[i][j - 1][c - 1][val];
                        dp[i][j][c][map[i][j]] %= MOD;
                        dp[i][j][c][map[i][j]] += dp[i - 1][j][c - 1][val];
                        dp[i][j][c][map[i][j]] %= MOD;
                    }
                }
            }
        }
    }
    
    int sum = 0;
    for(i = 0; i <= aMax; i++)
    {
        sum += dp[n][m][k][i];
        sum %= MOD;
    }
    printf("%d", sum);
    return 0;
}

/*
歷屆試題 斐波那契

問題描述
  斐波那契數列大家都非常熟悉。它的定義是:

  f(x) = 1 .... (x=1,2)
  f(x) = f(x-1) + f(x-2) .... (x>2)

  對於給定的整數 n 和 m,我們希望求出:
  f(1) + f(2) + ... + f(n) 的值。但這個值可能非常大,所以我們把它對 f(m) 取模。
  公式如下
        圖片百度 

  但這個數字依然很大,所以需要再對 p 求模。
輸入格式
  輸入為一行用空格分開的整數 n m p (0 < n, m, p < 10^18)
輸出格式
  輸出為1個整數,表示答案
樣例輸入
2 3 5
樣例輸出
0
樣例輸入
15 11 29
樣例輸出
25
*/
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <sstream>
#include <iostream>
#include <algorithm>

using namespace std;

#define PB push_back
#define MP make_pair
#define AA first
#define BB second
#define OP begin()
#define ED end()
#define SZ size()
#define SORT(x) sort(x.OP,x.ED)
#define SQ(x) ((x)*(x))
#define SSP system("pause")
#define cmin(x,y) x=min(x,y)
#define cmax(x,y) x=max(x,y)
typedef long long LL;
typedef pair<int, int> PII;
const double eps=1e-8;
const double INF=1e20;
const double PI=acos( -1. );
const int MXN = 50;
const LL MOD = 1000000007;
LL llmul( LL a,LL b,LL mod ) {
    a%=mod;a+=mod;a%=mod;
    b%=mod;b+=mod;b%=mod;
    if ( a<b )swap( a,b );
    LL ret=0;
    while ( b ) {
        if ( b&1 )ret=( ret+a )%mod;
        a=( a<<1 )%mod;
        b/=2;
    }
    return ret;
}
struct matrix {
    LL x[3][3];
    matrix() {memset( x,0,sizeof x );}
};
matrix mmul( matrix &A,matrix &B,LL mod ) {
    matrix ret;
    for ( int i=1; i<=2; i++ )
        for ( int j=1; j<=2; j++ )
            for ( int k=1; k<=2; k++ )
                ret.x[i][j]=( ret.x[i][j]+llmul( A.x[i][k],B.x[k][j],mod ) )%mod;
    return ret;
}
matrix E;
matrix A;
LL fib( LL n,LL mod ) {
    matrix O=E,B=A;
    while ( n ) {
        if ( n&1 )O=mmul( O,B,mod );
        B=mmul( B,B,mod );
        n/=2;
    }
    return O.x[1][2];
}

LL solve( LL n,LL m,LL mod ) {

    LL t=n/m;

    LL p=t/2,q=t%2;

    LL fuhao=p*m%2==0?1:-1;
    if ( q==0 ) {
        LL ans=fib( n%m,mod )*fuhao;
        ans%=mod;
        ans+=mod;
        return ans%mod;
    }
    if ( n%m==0 )return 0;

    LL x=(llmul(fib(n%m,mod),fib(m-1,mod),mod)*fuhao%mod+mod)%mod;
    LL y=fib(m,mod);
    LL a=fib(n%m-1,mod);
    if(n%m%2==0)a--;
    if(fuhao<0)a++;
    a=(a%mod+mod)%mod;

    return ((x-llmul(a,y,mod))%mod+mod)%mod;
}
int main() {
    int i,j;
    A.x[1][2]=A.x[2][1]=A.x[2][2]=1;
    E.x[1][1]=E.x[2][2]=1;
    LL n,m,mod;
    while ( cin>>n>>m>>mod )
        cout<<( solve( n+2,m,mod )-1+mod )%mod<<endl;
    return 0;
}

/*
歷屆試題 波動數列

問題描述
  觀察這個數列:
  1 3 0 2 -1 1 -2 ...

  這個數列中後一項總是比前一項增加2或者減少3。

  棟棟對這種數列很好奇,他想知道長度為 n 和為 s 而且後一項總是比前一項增加a或者減少b的整數數列可能有多少種呢?
輸入格式
  輸入的第一行包含四個整數 n s a b,含義如前面說述。
輸出格式
  輸出一行,包含一個整數,表示滿足條件的方案數。由於這個數很大,請輸出方案數除以100000007的餘數。
樣例輸入
4 10 2 3
樣例輸出
2
樣例說明
  這兩個數列分別是2 4 1 3和7 4 1 -2。
資料規模和約定
  對於10%的資料,1<=n<=5,0<=s<=5,1<=a,b<=5;
  對於30%的資料,1<=n<=30,0<=s<=30,1<=a,b<=30;
  對於50%的資料,1<=n<=50,0<=s<=50,1<=a,b<=50;
  對於70%的資料,1<=n<=100,0<=s<=500,1<=a, b<=50;
  對於100%的資料,1<=n<=1000,-1,000,000,000<=s<=1,000,000,000,1<=a, b<=1,000,000。
*/
#define mod 100000007
int n,s,a,b,x[1001][1001],i,j,t;
fun()
{
    while(x[i+1][t]>=mod)x[i+1][t]-=mod;
}
int main()
{
    scanf("%d%d%d%d",&n,&s,&a,&b);
    b%=n;
    b*=-1;
    while(b<0)b+=n;
    a%=n;
    s%=n;
    while(s<0)s+=n;
    for(i=0;i<n;i++)
        for(j=0;j<n;j++)
            x[i][j]=0;
    x[1][a]=x[1][b]=1;
    for(i=1;i<n-1;i++)
        for(j=0;j<n;j++)
        {
            t=(j+a*(i+1))%n;
            x[i+1][t]+=x[i][j];
            fun();
            t=(j+b*(i+1))%n;
            if(t>=n)
                t-=n;
            x[i+1][t]+=x[i][j];
            fun();
        }
    printf("%d\n",x[n-1][s]);
    return 0;
}

/*
歷屆試題 小朋友排隊

問題描述
  n 個小朋友站成一排。現在要把他們按身高從低到高的順序排列,但是每次只能交換位置相鄰的兩個小朋友。

  每個小朋友都有一個不高興的程度。開始的時候,所有小朋友的不高興程度都是0。

  如果某個小朋友第一次被要求交換,則他的不高興程度增加1,如果第二次要求他交換,則他的不高興程度增加2(即不高興程度為3),依次類推。當要求某個小朋友第k次交換時,他的不高興程度增加k。

  請問,要讓所有小朋友按從低到高排隊,他們的不高興程度之和最小是多少。

  如果有兩個小朋友身高一樣,則他們誰站在誰前面是沒有關係的。
輸入格式
  輸入的第一行包含一個整數n,表示小朋友的個數。
  第二行包含 n 個整數 H1 H2 … Hn,分別表示每個小朋友的身高。
輸出格式
  輸出一行,包含一個整數,表示小朋友的不高興程度和的最小值。
樣例輸入
3
3 2 1
樣例輸出
9
樣例說明
  首先交換身高為3和2的小朋友,再交換身高為3和1的小朋友,再交換身高為2和1的小朋友,每個小朋友的不高興程度都是3,總和為9。
資料規模和約定
  對於10%的資料, 1<=n<=10;
  對於30%的資料, 1<=n<=1000;
  對於50%的資料, 1<=n<=10000;
  對於100%的資料,1<=n<=100000,0<=Hi<=1000000。
*/
#include<stdio.h>

int h[100100];
int un[100100];

int b[1000100];
int reb[1000100];

int Lowbit(int x){
    return x&(x^(x-1));
}

int sum(int bit[], int idx){
    int ret = 0;
    while(idx > 0){
        ret += bit[idx];
        idx -= Lowbit(idx);
    }
    return ret;
}

void add(int bit[], int idx, int val){
    while(idx < 1000100){
        bit[idx] += val;
        idx += Lowbit(idx);
    }
}

long long uVal[100100];

int main(void){
    int n, i;
    scanf("%d", &n);
    uVal[0] = 0;
    for(i = 0; i < n; i++){
        scanf("%d", &h[i]);
        h[i]++;
        uVal[i + 1] = uVal[i] + i + 1;
        
        un[i] += i - sum(b, h[i]);
        add(b, h[i], 1);
    }
    long long ans = 0;
    for(i = n - 1; i >= 0; i--){
        un[i] += sum(reb, h[i] - 1);
        add(reb, h[i], 1);
        
        ans += uVal[un[i]];
    }
    printf("%I64d\n", ans);
    return 0;
}

/*
歷屆試題 分糖果

問題描述
  有n個小朋友圍坐成一圈。老師給每個小朋友隨機發偶數個糖果,然後進行下面的遊戲:

  每個小朋友都把自己的糖果分一半給左手邊的孩子。

  一輪分糖後,擁有奇數顆糖的孩子由老師補給1個糖果,從而變成偶數。

  反覆進行這個遊戲,直到所有小朋友的糖果數都相同為止。

  你的任務是預測在已知的初始糖果情形下,老師一共需要補發多少個糖果。
輸入格式
  程式首先讀入一個整數N(2<N<100),表示小朋友的人數。
  接著是一行用空格分開的N個偶數(每個偶數不大於1000,不小於2)
輸出格式
  要求程式輸出一個整數,表示老師需要補發的糖果數。
樣例輸入
3
2 2 4
樣例輸出
4
*/
#include <stdio.h>
#include <malloc.h>
int count=0;
void f(int n,int *m)
{
    int j,temp=m[0];
    for(j=n-1;j>0;j--)
        m[(j+1)%n]+=(m[j]/=2);
    m[1]+=temp/2;
    m[0]-=temp/2;
    for(j=0;j<n;j++)
    {
        if(m[j]%2!=0)
        {
             m[j]++;
             count++;
        }
    }
}
int jisuan(int n,int *m)
{
    int j;
    for(j=0;j<n-1;j++)
        if(m[j]!=m[j+1]) return 0;
    return 1;
}
int main()
{
    int n,j;
    scanf("%d",&n);
    int *m=(int*)malloc(sizeof(int)*n);
    for(j=0;j<n;j++)
        scanf("%d",&m[j]);
    do
    {
        f(n,m);
    }
    while(jisuan(n,m)!=1);
    printf("%d",count);
    return 0;
}

/*
歷屆試題 蘭頓螞蟻

問題描述

    圖形百度 
  蘭頓螞蟻,是於1986年,由克里斯·蘭頓提出來的,屬於細胞自動機的一種。

  平面上的正方形格子被填上黑色或白色。在其中一格正方形內有一隻“螞蟻”。
  螞蟻的頭部朝向為:上下左右其中一方。

  螞蟻的移動規則十分簡單:
  若螞蟻在黑格,右轉90度,將該格改為白格,並向前移一格;
  若螞蟻在白格,左轉90度,將該格改為黑格,並向前移一格。

  規則雖然簡單,螞蟻的行為卻十分複雜。剛剛開始時留下的路線都會有接近對稱,像是會重複,但不論起始狀態如何,螞蟻經過漫長的混亂活動後,會開闢出一條規則的“高速公路”。

  螞蟻的路線是很難事先預測的。

  你的任務是根據初始狀態,用計算機模擬蘭頓螞蟻在第n步行走後所處的位置。
輸入格式
  輸入資料的第一行是 m n 兩個整數(3 < m, n < 100),表示正方形格子的行數和列數。
  接下來是 m 行資料。
  每行資料為 n 個被空格分開的數字。0 表示白格,1 表示黑格。

  接下來是一行資料:x y s k, 其中x y為整數,表示螞蟻所在行號和列號(行號從上到下增長,列號從左到右增長,都是從0開始編號)。s 是一個大寫字母,表示螞蟻頭的朝向,我們約定:上下左右分別用:UDLR表示。k 表示螞蟻走的步數。
輸出格式
  輸出資料為兩個空格分開的整數 p q, 分別表示螞蟻在k步後,所處格子的行號和列號。
樣例輸入
5 6
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
2 3 L 5
樣例輸出
1 3
樣例輸入
3 3
0 0 0
1 1 1
1 1 1
1 1 U 6
樣例輸出
0 0
*/
#include<stdio.h>
int a[1000][1000]={
    0
};
char f(int i,char now)
{
    if(i==0&&now=='U'||i==1&&now=='D')
      return 'R';
    else if(i==0&&now=='R'||i==1&&now=='L')
      return 'D';
    else if(i==0&&now=='D'||i==1&&now=='U')
      return 'L';
    else if(i==0&&now=='L'||i==1&&now=='R')
       return 'U';
    
}
int main()
{
    int n,m,i1,i2,x,y,k;
    char s;
    scanf("%d%d",&n,&m);
    for(i1=0;i1<n;i1++)
       for(i2=0;i2<m;i2++)
           scanf("%d",&a[i1][i2]);
    scanf("%d%d",&x,&y);
    getchar();
    scanf("%c%d",&s,&k);
    char now=s;
    while(k--)
    {  if(a[x][y]==0)
           a[x][y]=1;
       else 
          a[x][y]=0;
       
       now=f(a[x][y],now);
       if(now=='U')
           x--;
        else if(now=='D')
            x++;
       else if(now=='L')
           y--;
       else
           y++;
            
    }  
    printf("%d %d\n",x,y);
    return 0;
}

/*
歷屆試題 矩陣翻硬幣

問題描述
  小明先把硬幣擺成了一個 n 行 m 列的矩陣。

  隨後,小明對每一個硬幣分別進行一次 Q 操作。

  對第x行第y列的硬幣進行 Q 操作的定義:將所有第 i*x 行,第 j*y 列的硬幣進行翻轉。

  其中i和j為任意使操作可行的正整數,行號和列號都是從1開始。

  當小明對所有硬幣都進行了一次 Q 操作後,他發現了一個奇蹟——所有硬幣均為正面朝上。

  小明想知道最開始有多少枚硬幣是反面朝上的。於是,他向他的好朋友小M尋求幫助。

  聰明的小M告訴小明,只需要對所有硬幣再進行一次Q操作,即可恢復到最開始的狀態。然而小明很懶,不願意照做。於是小明希望你給出他更好的方法。幫他計算出答案。
輸入格式
  輸入資料包含一行,兩個正整數 n m,含義見題目描述。
輸出格式
  輸出一個正整數,表示最開始有多少枚硬幣是反面朝上的。
樣例輸入
2 3
樣例輸出
1
資料規模和約定
  對於10%的資料,n、m <= 10^3;
  對於20%的資料,n、m <= 10^7;
  對於40%的資料,n、m <= 10^15;
  對於10%的資料,n、m <= 10^1000(10的1000次方)。
*/
#include<stdio.h>
#include<string.h>
#define MAX 1000 + 10

int  minu[MAX], sub[MAX], sq[MAX];
int x;

int main()
{
    void sqrt_int ( char * , int ) ;  
    char n[MAX], m[MAX];  scanf ( "%s" , n ) ; scanf ("%s" , m ) ;
    int a[MAX], b[MAX], s[MAX], S[MAX]; int c, i, j, k, na, nb;
    int len_n , len_m ;
    memset ( a, 0, sizeof (a) ) ; memset ( b, 0, sizeof (b) ) ;
    memset ( s, 0, sizeof (s) ) ; memset ( S, 0, sizeof (S) ) ;
    
    len_n = strlen (n) , len_m = strlen (m) ;  

    sqrt_int ( n, len_n ) ; for ( na = x, i = 0 ; x >= 0 ; i ++ )  a[i] = sq[x--] ;
    sqrt_int ( m, len_m ) ; for ( nb = x, i = 0 ; x >= 0 ; i ++ )  b[i] = sq[x--] ;

    for ( i = 0 ; i <= na ; i ++ )
    {
        for ( k = i, c = j = 0 ; j <= nb+1 ; j ++ , k ++ )
        {
            s[k] = (a[i] * b[j]) % 10 + c ; 
            c = (a[i] * b[j]) / 10 ;
            if (s[k] >= 10 )  { s[k] -= 10 ; c ++ ; }  
            S[k] += s[k] ; if ( S[k] >= 10 )  { S[k] -= 10 ; S[k+1] ++ ; }
        }
    }
    for ( i = MAX-1 ; i >= 0 ; i -- )  if (S[i])  break ;
    for ( j = i ; j >= 0 ; j -- )  printf ("%d" , S[j] ) ;
    putchar ('\n') ;

    return 0;
}

void sqrt_int ( char *minu_char , int len ) 
{
    int i, j, k, m;  
    int s, c, flag;
    int first, num;
    memset ( minu, 0, sizeof (minu) ) ;
    memset ( sub, 0, sizeof (sub) ) ;
    memset ( sq, 0, sizeof (sq) ) ;

    if ( len % 2 ) 
    {
        minu[0] = minu_char[0] - '0' ;  
        for ( num = 3 ; num >= 0 ; num -- )  if ( minu[0] >= num*num )  break ; 
        sq[x=0] = num ; minu[0] -= num*num ; first = 1 ; 
        
    }
    else 
    {
        sq[x=0] = 0 ; first = 0 ; 
    }

    for ( i = first ; i < len ; i += 2 ) 
    {
        minu[i] = minu_char[i] - '0' ; minu[i+1] = minu_char[i+1] - '0' ;
        
        memset (sub , 0, sizeof (sub) ) ; 
        for ( k = 9 ; k >= 0 ; k -- ) 
        {
            sub[i+1] = k ; c = 0 ;   
            for ( m = i , j = x ; j >= 0 ; j -- , m -- ) 
            {
                s = sq[j] * 2 ;
                sub[m] = s % 10 + c ;
                c = s / 10 ;
            }
            sub[m] = c ; c = 0 ;

            for ( m = i+1 ; m >= 0 ; m -- )  
            {
                s = sub[m] * k ;
                sub[m] = s % 10 + c ;
                c = s / 10 ;
                if (sub[m] >= 10 )  { sub[m] -= 10 ; c ++ ; }
            }

            for ( flag = m = 0 ; m <= i+1 ; m ++ )  
            {
                if (minu[m] < sub[m])  { flag = 1 ; break ; }
                else if (minu[m] > sub[m] )  break ; 
            }

            if ( !flag )  
            {
                for ( m = i+1 ; m >= 0 ; m -- )  
                {
                    if ( minu[m] < sub[m] )  { minu[m] += 10 ; minu[m-1] -- ; }
                    minu[m] -= sub[m] ;
                }
                sq[++x] = k ; break ;
            }
            else  memset (sub, 0, sizeof (sub) ) ;  
        }
    } 
}

AllOver