AOAPC I: Beginning Algorithm Contests (Rujia Liu) Volume 6. Mathematical Concepts and Methods

uva 106 這題說的是 說計算 x^2 + y^2  =  z^2  xyz 互質 而後計算個數和 在 N內 不在 勾股數以內的數的個數 而後去找須要的 ios

維基百科上 看到 另 n*m*2 =b     n*n+m*m=c  m*m-n*n = a  m>n 而後這樣能夠計算出 全部互質的 勾股數 而後進行枚舉n和m 進行判斷 還有一個問題他爲何不會遺漏 互質的勾股數呢   我本身想了一下 應該是這樣的  也就是說 n^2 和 m^2  必須爲整數 就是說 他們是分數已經不可能了 那如今來討論 他們是帶根號的時候的數 也就是說 存在這樣的數 那麼當n*m 必須爲整數 能夠知道 如 果 有 一 個 爲 根 號 那 麼 必 須 兩 個 都 帶 有 那麼能夠知道他們最簡根式根號內的東西必須是同樣的 那麼 若是同樣就致使了 b 和 c 具 有 一 樣 的公約數 而後就不成立了  那麼 n和m 必須爲 整數less

若須要一組最小數爲奇數的勾股數,可「任意選取」一個大於1的奇數,也就是3或以上的奇數,將該數自乘爲平方數,除以2,答案加減0.5可獲得兩個新的數字,這兩個數字連同一開始選取的奇數,三者一定造成一組勾股數。但卻不必定是以這個選取數字爲起首勾股數的惟一可能,例如(27,364,365)並不是是以27爲起首的惟一勾股數,由於存在另外一個勾股數是(27,36,45),一樣也以27爲首。ide

#include <iostream>
#include <cstdio>
#include <string.h>
#include <cmath>
using namespace std;
const int maxn = 1000005;
int es[1005],N;
bool mark[maxn];
int gcd(int a, int b){
    return b==0?a:gcd(b,a%b);
}
void jud(int x,int y,int z){

    for(int i = 1 ; i <=N ; i ++){
        if(i*z>N)break;
        mark[i*x] = true;
        mark[i*y] = true;
        mark[i*z] =true;
    }
}
int main()
{
    for(int i = 1; i <= 1000 ; ++i)
         es[i] =  i*i;
    while(scanf("%d",&N) == 1){
        for(int i = 0 ; i <= N ; ++ i )
            mark[i] = false;
        int ans = 0,p=0,T=sqrt(N+0.5);
        for(int n = 1 ; n<=T ; n++){
             for( int m =n+1 ; m<=T ; m ++){
                 if(es[n]+es[m] > N) break;
                 if(gcd(n,m) != 1|| (n%2&&m%2)) continue;
                 int x= es[m]-es[n];
                 int y= 2*m*n;
                 int z= es[m] +es[n];
                    ans ++;
                    jud(x,y,z);
                 }
             }


        for(int i = 1 ; i <= N ; ++ i) if(mark[i]==false) p++;
        printf("%d %d\n",ans,p);

    }
    return 0;
}
View Code

uva 10673 這題說的是 就是算出使得 X/K 向下取整 和X/K向上取整 發現當能整除的時候直接輸出 0 K 不然輸出 -X 和 X 由於他們只差1函數

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
typedef long long LL;
int main()
{
     int t;
     scanf("%d",&t);
     while(t -- ){
        long long  X,K;
        cin>>X>>K;
         if(X%K == 0){

             cout<<0<<' '<<K<<endl; continue;
         }
          cout<<-X<<' '<<X<<endl;
     }

    return 0;
}
View Code

 uva11121 這題說的是給了一個數 叫你將他改寫爲 -2 進制的數  能夠知道 當數字是大於0 的時候 位置在 奇數位的時候 2^k   =  2^(k+1)  - 2 ^(k) 次方  而後就會獲得 每一個位置上 的個數 能夠知道 (-2)^k   (-2)^(k+2) +(- 2)^(k+1) 而後 這樣進行轉化 獲得    到最後 可會出現循環  循環的緣由是 2*(-2)^k  == (-2)*(k+1)  對於這樣的數能夠削去 而後就獲得了ui

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
int num[150];
int  jud(int cas,int t, int n){
      int loc = 0;
      memset(num,0,sizeof(num));
      while( n ){
          if( n%2 == 1 ){
             if(loc%2!=t)
                   ++num[loc+1];

                 ++num[loc];
          }
         loc++;
         n=n/2;
      }
      for(int i =0 ; i <150-2 ; i ++)
      while(num[i]>1){
          num[i]-=2;
          num[i+1]++; num[i+2]++;
      }
        printf("Case #%d: ",cas);
      for(int i = 100-2 ; i >0 ;i --){
             if(num[i]!=0){
                 for( int j = i ; j >0 ; j --)
                   printf("%d",num[j]);
               break;
             }

      }
      printf("%d\n",num[0]);
     return 0;
}
int main()
{
     int t;
     scanf("%d",&t);
    for(int cas =1 ; cas <= t; ++ cas ){
           int  n ;
           scanf("%d",&n);
           if(n>=0){
            jud(cas,0,n);
           }
           else{
               jud(cas,1,-n);
           }
     }

    return 0;
}
View Code

 uva10791 這題說的是給了 一個數字 而後讓你計算出 大於等於 兩個 數的 最小公倍數是 N 而後使得 這些數字的和最小   咱們能夠這麼想這些數字能組成 最小公倍數是 n 應該使得這些數之間的 最大公約數爲 1 這樣或許能夠減小一些值 而後 咱們能夠想象 一下 若是 最小公倍數 能夠用 2 個數字 表示也能夠 用3 個數字 表示 那麼這顯然是用3個數字表示和值會比較小,由於他們那個畢竟是加 和乘的差異 而後就獲得瞭解在邊界問題上wa 了一次 而後 改了一下 T 了 範圍改小點就A 了this

#include <iostream>
#include <cstdio>
#include <string.h>
#include <cmath>
using namespace std;
const int inf = 0x7fffffff;
int prime[10000];
bool vis[100000];
int main()
{

      memset(vis,false,sizeof(vis));
        long long N = 50000;
        long long num = 0;
        for(long long  i = 2 ; i<=N; i ++)
        if(vis[i] == false){
              prime[num++] = i;
              for(long long  j = i*i ; j <= N ; j+=i )vis[j] = true;
        }
        long long n,cas =0;

        while(true){
            scanf("%lld",&n);
            if(n == 0 ) break;
            long long loc = 0,ans =0,ge=0;
            while(loc<num &&n>1){
                 bool fal = false;
                int t=1;
                while(n%prime[loc] == 0){
                     t =t *prime[loc];
                     n = n / prime[loc];
                     fal = true;
                }
                if(fal) {
                        ans += t;
                         ge ++;
                }
                loc++;
            }
            if( ge == 0 ){
                ans = n+1;
            }
            else if(ge==1 && n==1) ans += 1;
            else if(n!=1) ans +=n;
             printf("Case %lld: %lld\n",++cas,ans);
        }
       return 0;
}
View Code

 uva 10717 這題說的是 給了不少種硬幣厚度 每張桌子有 4 條腿 每條腿 只能用一種 硬幣 一張桌子必須用 4種硬幣 而後枚舉往往四種硬幣  求最小公倍數spa

#include <iostream>
#include <string.h>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 3000000;
const long long inf =1000000000000000000;
long long  hight[55];
long long to[maxn];
long long gcd(long long  a,long long b){
     return b== 0?a:gcd(b,a%b);
}
long long minv(long long a, long long b){
   return a>b?b:a;
}
int main()
{
     int n,tt,num;
     while(scanf("%d%d",&n,&tt) == 2){
            if(n == 0 && tt  ==  0 ) break;
        int r =0;
       for(int i = 0 ; i < n ; ++ i)
        {
            cin>>hight[r];
            if(hight[r] == 0 )continue;
            r++;
        }
        n =r;
        num =0;
        for(int i = 0 ; i < n-3 ; ++ i )
            for(int j = i+1 ; j < n-2 ; ++ j){

                    long long y1 = gcd(hight[i] , hight[j]);

                    long long ans1 = hight[i] * hight[j] / y1;

                    for(int k = j+1 ;k <n - 1; ++ k){

                        long long y2 = gcd(ans1, hight[k]);

                        long long ans2 = hight[k] * ans1 /y2;

                        for(int t = k +1 ; t < n ; ++t ){

                           long long y3 = gcd(ans2, hight[t]);

                           long long  ans3 = hight[t] * ans2 /y3;

                           to[ num ++ ] =ans3;
                        }
                    }
                }



        for(int i = 0 ; i < tt ; ++ i){
            long long ans;
            cin>>ans;
            long long L = inf , R = inf;

            for(int j = 0 ; j < num ; ++ j){
                long long t = ans % to[j];
                if(ans <= to[j]){
                    L = minv( L , ans);
                    R = minv(R , to[j] - ans);
                }
                else {
                    L = minv(L,t);
                    R =minv(R,(to[j]-t)%to[j]);
                }
                if(L == 0 && R == 0) break;
            }
            cout<<ans - L<<' '<<ans + R<<endl;
        }
     }
     return 0;
}
View Code

 uva 11027 這 題 說 的 是 給 了 一 個 字 符 串 輸 出 回 文 串 輸 出 第 n 大 的 回 文 字 符 串 的 剛開想 經過數學相似康託展開的東西去 映射 發現不行 畢竟不支持有重點的,仍是沒想法 看了解題報告後才知道用枚舉每一位的逼近所要的數值 儘可能取字典序小的放在前面若是 方案數小於 n 就用 n-num 不然就 直接下一個位忘了能夠用這種方法解決 嗨思惟須要活躍一點啊啊啊啊啊3d

#include <iostream>
#include <cstdio>
#include <string.h>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long LL;
LL f[16],n,len,add;
char str[30],output[30],cap;
int num[26],number[26];
vector<char>t;
LL jud(int nn, int tr){
   LL add = 1;
   num[tr]--;
   for(int i = 0 ; i < 26 ; i++)
     add*=f[num[i]];
   num[tr]++;
   return f[nn]/add;
}
void solve(int L){
     int ge = 0;
     t.clear();
     for(int i = 0 ; i<26 ; ++ i){
          for(int j = 0 ; j<num[i] ; ++ j)
              t.push_back('a'+i);
     }
     sort(t.begin(),t.end());
     LL sum;
     for(int i =0;  i<L; ++ i ){
        int tr;
         for(tr = 0 ; tr<t.size() ; ++ tr){
             if(tr!=0&&t[tr-1] == t[tr] ) continue;
            sum = jud(L-1-i,t[tr]-'a');
            if(sum>=n)break;
            n-=sum;
         }
         output[ge++]=t[tr];
         num[t[tr]-'a']--;
         t.erase(t.begin()+tr);
     }
     if(len%2)output[ge++]= cap;
     for(int i = 0 ; i<L ; ++ i)
         output[ge++] = output[L-1-i];
}
int main()
{
     f[0] = 1;
    for(int i = 1 ; i<=15; ++ i)
         f[i]=f[i-1]*i;
    int t;
    scanf("%d",&t);
    for(int cas = 1 ;cas <= t ;cas ++ ){
        scanf("%s%lld",str,&n);
        memset(num,0,sizeof(num));
        memset(number,0,sizeof(number));
        len  = strlen(str);
        for(int i = 0 ; i<len; ++ i)
             num[str[i]-'a']++;
        int oddNum = 0;
        for(int i = 0 ; i<26 ; ++ i ){
            number[i] = num[i];
            if(num[i]%2) {++oddNum ;  cap = 'a' +i ;}
            num[i]=num[i]/2;
        }
        if(oddNum>1){ printf("Case %d: XXX\n",cas); continue;}
        int L = len / 2 ;
        add =1;
        LL permutationNum = f[L];
        for(int i = 0 ; i < 26 ; ++ i)
            if(num[i]>0)
              {permutationNum /=f[ num[ i ] ]; add*=f[num[i]];}
        if( n > permutationNum ){
            printf("Case %d: XXX\n",cas); continue;
        }
        solve(L);
             output[ len ] = 0;
            printf("Case %d: %s\n",cas,output);
    }
    return 0;
}
View Code

 

 uva 10820 這題說的是 給了一個數N 這個 N是大於1 小於50001的數 而後計算出 使得在小於等於N的 數 中 有對少 對互質的數,(1,2)和(2,1)算不一樣,  用白書上的歐拉函數解決就行了 ,歐拉函數計算小於等於n的 與n互質的個數,將結果乘以2 加一塊兒就 好了 得去了解一下中國剩餘定理了code

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn =50001;
long long num[maxn];
long long ans[maxn];
void intial(){
    memset(ans,0,sizeof(ans));
    memset(num,0,sizeof(num));
    ans[1]=num[1] = 1;
    for(int i = 2 ; i < maxn ; ++ i){
         if(num[i]==0){
            for(int j = i ; j <= maxn ; j += i){
                if(num[j]== 0) num[j] = j;
                num[j]= num[j]/i*( i - 1 );
                }
        }
         ans[i]+=ans[i-1]+num[i]*2;
    }
}

int main()
{
       intial();
         while(true){
              int n;
              scanf("%d",&n);
              if(n == 0) break;
              printf("%lld\n",ans[n]);
         }
        return 0;
}
View Code

 uva 5 7 1 這題說的是 給了 兩個杯子和一個體積 這兩個 杯子 分別 是A 和 B ,B的體積大於A的體積,給了 一個體積 假設爲 N ,而後 最後使得 B 中 擁有N 體積的水 N<B<100, A與B 互質, 這樣就使得,A 和 B 能夠拼獲得任意體積的水(小於B的) 而後由於能夠列的這樣的一個方程(Ax+By=N(呵呵 x不斷的在增長))這樣就獲得了,應該要求的 將 A 中的 水不斷的往B中倒知道知足N體積的水。orm

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn =50001;
int A,B,N,x,y,gcd;
int main()
{
         int inA,inB;
         while( scanf("%d%d%d",&A,&B,&N) == 3 ){
                inA = 0;
                inB = 0;
                while(true){
                      if( inB == N ){   break;  }
                      if(inA == 0){
                         puts("fill A"); inA+=A;
                      }else if(inA < A){
                         puts("pour A B"); inB = inA; inA= 0;
                      }
                      else {
                           if( B-inB <= inA){
                               puts("pour A B");
                               inA -= B-inB;
                               inB = B;
                               if(inB == N) break;
                               puts("empty B");
                                inB=0;
                            }
                            else {
                                puts("pour A B");
                                inB +=inA;
                                inA = 0;

                            }
                      }
                }
              puts("success");
        }
        return 0;
}
View Code

 uva 11029 這題說的是 給了一個整數 N 求 N的K次方,N在int 範圍內 K 在10000001 計算出該數的前 3 位 和 後 3 位 ,後三位 天然用 快速冪解決 ,前三位須要用到 log 對數,由於N^K次方很大,咱們對他求一次 log 就獲得了g 而後取整數部分爲何取整數部分就ok了呢 由於10^(G.H)(G爲整數部分H爲小數部分) = 10^G*10^0.H次方這樣就能夠知道了G只起到調整小數點位置的做用沒有其餘的做用這樣將他省略了, 答案在乘上一個100就ok了

#include <iostream>
#include <cstdio>
#include <string.h>
#include <cmath>
using namespace std;
int k_pow(int a,int n){
      int ans = 1 ;
      a=a%1000;
      while(n){
          if(n&1){
             ans = (ans*a)%1000;
          }
          a=(a*a)%1000;
          n=n/2;
      }
      return ans;
}
int main()
{
     int cas ,A,B;
      scanf("%d",&cas);
        while( cas -- ){
           scanf("%d%d",&A,&B);
           int ans2 = k_pow(A,B);
           double tr = double(B)*log10(A*1.0);
            tr=tr-(int )tr;
            tr=100*pow(10,tr);
            printf("%d...%03d\n",int(tr),ans2);
        }
        return 0;
}
View Code

 uva 10023 這 題 說 的 是 給 了 一 個 10  的 1000 次 方 以 內 的 數 要 對 它 進 行 開 方 自 然 精 確 到 整 數 就 好。 事 先 理 解 一 下 這 個 東 西 ( A B )A 是 10 位 上 的 數 字 B 是 個 位 上 的 數 字 

(AB)^ 2 = (100*A) + 20 * B * A + B * B , 那麼能夠知道在這個數字的百位上的數字是應該讓A區得最大 且 A*A要小於等於這個數字百位上的數,這樣可讓這個數字更接近於開方出來後獲得的數字這顯然是正確的 這樣經給的大整數 從低位到高位進行一次兩位兩位的分割 而後從最低高位開始不斷的去嘗試使得最大的B適合這個開方出來的數,由於每次都考慮使得20 * B * A + B * B  最 大的B ,最高位的時候考慮A=0 成功後就將B添加到末尾,能夠這樣想前面的位置A已經符合了,而後接下來就剩考慮B了 根據這個20 * B * A + B * B  獲得最大的B 每次都向後面移兩位 不斷的去嘗試

#include <iostream>
#include <cstdio>
#include <string.h>
#include <cmath>
using namespace std;
const int maxn = 505 ;
const int mod = 100 ;
void swapc(char &a,char &b){ char c; c = a ; a = b ;b = c ;  }
struct Bignumber{
    int num[maxn],len;
    Bignumber(){
       memset(num,0,sizeof(num));
       len = 1 ;
    }
    void add(Bignumber &A,int &temp){
         while(temp){
             A.num[A.len++] = temp%mod;
             temp/=mod;
         }
    }
    void dec(Bignumber &A){
        while(A.num[A.len-1]==0&&A.len>1){
            A.len--;
        }
    }
    Bignumber(char *str){
        memset(num,0,sizeof(num));
        int L = strlen( str );
        for(int i = 0 ; i < L/2 ; ++ i )swapc( str[i] , str[L-i-1] );
        str[L]='0';
        L=( L + 1 )/2;
        len = 0;
        for(int i = 0 ; i  < L*2 ; i += 2  )
           num[ len ++ ]=str[i]-'0'+( str[i+1] - '0' ) * 10;
    }
    Bignumber operator +(int w){
          int temp = w;
          Bignumber ans;
          ans.len = len;
          for(int i = 0 ; i< len ;++ i){
               int r = num[i] + temp;
               ans.num[i] = r%mod;
               temp = r/mod;
          }
          add(ans,temp);dec(ans);
          return ans;
    }
    Bignumber operator +(Bignumber A){
         int L =max(len,A.len),temp =0;
         Bignumber ans;
         ans.len = L;
         for(int i = 0 ; i<L ; ++ i){
            int r = num[i] +A.num[i] +temp;
            ans.num[i] = r%mod;
            temp=r/mod;
         }
          add(ans,temp);dec(ans);
          return ans;
    }
    Bignumber operator *(int w){

          int temp = 0;
          Bignumber ans;
          ans.len = len;
          for(int i = 0 ; i < len ; ++ i){
             int r = num[i]*w +temp;
             ans.num[i] = r%mod;
             temp = r / mod;
          }
          add(ans,temp);dec(ans);
          return ans;
    }
    bool operator <(Bignumber A)const {
         if(len!=A.len) return len<A.len?true:false;
         for(int i = len -1 ; i >= 0 ; -- i)
             if(num[i]!=A.num[i]) return num[i]<A.num[i]?true:false;
        return true;
    }
    Bignumber operator - (Bignumber A){

           Bignumber ans;
           ans.len=len;
           for(int i = 0 ; i<len ;++ i)
               ans.num[i] = num[i] - A.num[i];
           for(int i = 0 ; i <len ; ++ i)
           if(ans.num[i]<0){
            ans.num[i]=ans.num[i]+mod;
            --ans.num[i+1];
           }
          dec(ans);
          return ans;
    }
    void output(){
        printf("%d",num[len -1]);
        for(int i =len -2 ; i>=0 ; -- i)
             printf("%02d",num[i]);
        printf("\n");
    }
};
char str[maxn*2];
int main()
{
       int cas;
      scanf("%d",&cas);
        while( cas -- ){
           scanf("%s",str);
           Bignumber T(str);
           Bignumber ans,cmp;
           Bignumber temp ;
           for(int i = T.len -1 ; i>=0 ; -- i){
                cmp=cmp*100;
                cmp =cmp + T.num[i];
                int b;
                for( b = 9 ; b>=0 ; b --){
                     temp = ans*(20*b);
                     temp = temp + (b*b);
                    if(temp<cmp) break;
                }
                cmp =cmp - temp;
                ans=ans*10+b;
           }
           ans.output();
           if(cas)puts("");
        }
        return 0;
}
View Code

 uva 10308 這題說的是給了一棵樹(the roads are built in such a way that there is only one route from a village to a village that does not pass through some other village twice)由這句話能夠獲得而後要求出樹上最遠的兩點,能夠知道樹上的一個點到另外一個點只有一條道路能夠走,這樣很顯然剛開始不知道怎麼搞,發現能夠任何選一個點,能夠知道他與他最遠的孩子距離 ,讓他的任意兩個孩子與他的距離相加 就獲得了這兩個孩子的最遠距離,這樣不斷的去取最大值,返回離他最遠距離的孩子的距離加上他與父節點的距離

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn=10005;
class edg{
   public :int to,dist,next;
   edg(int a=0,int b =0 ,int c =0){
       to =a; dist= b; next= c;
   }
};
edg E[maxn*2];
int first[maxn],Num,F[3],ans,S;
void read(char *str){
     int len = strlen(str),um=0,i=0;
     while(i<len){
        if(str[i]>='0'&&str[i]<='9'){
             int r=0;
             while(str[i]>='0'&&str[i]<='9' && i<len){
                 r=r*10+str[i]-'0';
                 ++ i;
             }
             F[um++]=r;
        }
        ++i;
     }
     if(S>min(F[0],F[1]))S =min( F[0] , F[1] );
     E[Num]=edg(F[1],F[2],first[F[0]]);
     first[F[0]] = Num++;
     E[Num]=edg(F[0],F[2],first[F[1]]);
     first[F[1]] = Num++;
}
int dfs(int occ , int per,int D){

    int dd = 0;
    for(int i = first[occ] ; i!=-1 ; i=E[i].next){
        int to = E[i].to ; int dist = E[i].dist ;
        if(to == per) continue ;
        int rt =dfs(to,occ,dist);
        ans = max(dd+rt,ans);
        dd= max(dd,rt);
    }
    return dd+D;
}
int main()
{
      char str[100];
     while(gets(str)){
          memset(first,-1,sizeof(first));
          Num = 0;
           S = 10000;
          if(strlen(str) == 0 ) {
             printf("0\n");continue;
          }
          ans = 0 ;
          read(str);
          while(gets(str)){
              if(strlen(str)==0) break;
              read(str);
          }

         dfs(S,-1,0);
         printf("%d\n",ans);
     }
     return 0;
}
View Code

 uva 10105 這題說的是多項式(x1+x2+x3+x4+x5...+xk)^n   計算x1^n1 * x2^n2 *x3^n3 *...*xk^nk 給了n1 n2..nk 計算該多項式的係數咱們能夠用二項式展開進行推廣(x1 + G(x))^n 這樣能夠獲得一個多項式爲 a1*x1^n1*(G(x))^(n-n1),按照二項式展開繼續去展開G(x) 能夠獲得咱們要求的 即a1*a2*a3*..*ak;

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn = 15;
int C[maxn][maxn];
int indexx[maxn];
int main()
{
      for(int i =0 ; i <= 13 ; ++ i){
        C[0][i]=1;
        for(int j = 1 ; j <= i ; ++ j)
          C[j][i] = C[ j - 1 ][ i - 1 ] + C[ j ][ i -1 ];
      }
      int n,k;
      while(scanf("%d%d",&n,&k) == 2 ){
          int ans =1;
          for(int i = 0 ; i< k ; ++ i)
             scanf("%d",&indexx[i]);
          for(int i = 0 ; i< k ; ++ i){
            ans*=C[indexx[i]][n];
            n-=indexx[i];
          }
         printf("%d\n",ans);
      }
      return 0;
}
View Code

 uva 這題說是 第 I 個 人 獲 得  勝 利 的 概 率 拋 一 枚 骰 子 第 一 次 扔 到 3 的人獲勝。p*k +R*(P+R(P+R(...)))

#include <iostream>
#include <cstdio>
#include <string.h>
#include <cmath>
using namespace std;
const double epl = 0.000001;
int eps(double a){
   if(fabs(a)<epl) return 0;
    return a>0?1:-1;
}
int main()
{
     int N,I,cas;
     double P;
     scanf("%d",&cas);
     while( cas -- ){
         scanf("%d%lf%d",&N,&P,&I);
         double R = 1 ,ans=0,cur=1;
         for(int i = 1 ; i<I ; ++i )
             R=R*(1-P);
             cur = R;
         for(int i= I+1 ; i <= N ; ++ i){
                R=R*(1-P);
             }
         while(eps((ans+cur*P) - ans )>0){
              ans+=cur*P;
              cur=cur*R*(1-P);
         }
         printf("%.4lf\n",ans);
     }

    return 0;
}
View Code

 化簡後能夠發現是一個等比數列 由於(q)《1 當w趨於無窮多項的時候(q)^w趨於0 因而就獲得了

#include <iostream>
#include <cstdio>
#include <string.h>
#include <cmath>
using namespace std;
int main()
{
     int N,I,cas;
     double P;
     scanf("%d",&cas);
     while( cas -- ){
         scanf("%d%lf%d",&N,&P,&I);

         double ans=0;
         if(0.0!=P)
         ans = pow( 1 - P , I - 1 ) * P /( 1 - pow( 1 - P , N ) );
         printf("%.4lf\n",ans);
     }

    return 0;
}
View Code

 uva10491 這題說的是 在一個電視節目中 有 N 個 們 其 中 有 a 個 門 後 是 汽 車 b 個 門 後 是 牛 (a+b)等於N  而後 讓 你 選 擇 你 先 選 中 其 中 一 個 門這個門 就被淘汰了 接下來主持人會將剩下K個門後是牛的 門 打開 在沒有打開的門中你再選 選中是汽車的機率 列一個式子(b/N)*(a/(N-K-1))+(a/N)*((a-1)/(N-K-1));

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;

int main()
{
       int ncow,ncar,nshow;
       while(scanf("%d%d%d",&ncow,&ncar,&nshow) == 3 ){
            double ans = (double (ncow)/double(ncow+ncar))*(double (ncar)/double(ncow+ncar-1-nshow))
            +  (double (ncar)/double(ncow+ncar))*(double (ncar-1)/double(ncow+ncar-1-nshow));
           printf("%.5lf\n",ans);
       }


      return 0;
}
View Code

 uva 10759 這題說的是給了 n個正常的骰子而後 計算 這n個骰子的和 大於等於 x 的機率是多大首先用dp計算出dp[n][x] 的值 表示的是 n個骰子的和爲x 的方案總數,能夠獲得這樣的動態方程dp[n][x]+=(dp[n-1][x-k])(k>1&&k<=6)這樣計算出來的就是這n個點出現和x的方案總數了,由於能夠知道最後一個骰子有6中狀況 這六種狀況對應的上一個骰子在dp[n-][x-k]處的和 而後 壘加一下就ok了 由於對於每一個骰子只有6中狀態,好了這樣就能夠和分母進行約分了

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
long long dp[25][150],Th[25];
int main()
{
    long long ans =0;
    memset(dp,0,sizeof(dp));
    for(int i =0 ; i<25 ; ++ i ){
        dp[i][i]=1;
        for(int j =i+1; j<= i*6 ; ++ j){
            for(int k = 1 ;k<=6&&j-k+1>=i;  ++ k)
                    dp[i][j]+=dp[i-1][j-k];

        }
    }
    Th[0]=1;
    for(int i =1 ; i<=24 ;++i)
        Th[i]=Th[i-1]*6;
    int n,x;
    while(true){
        scanf("%d%d",&n,&x);
        if(n==0&&x==0 ) break;
        long long G=Th[n];
        ans = 0 ;
        for(int i = n ; i < x && i <= n*6 ; ++i )
            ans+=dp[n][i];
        ans=G-ans;
        while(ans%2==0&&ans>0&&G%2==0){
                G/=2; ans /= 2 ;
        }
        while(ans%3==0&&ans>0&&G%3 == 0){
               G/=3;  ans/=3;
        }
        if(ans%G==0) printf("%lld\n",ans/G);
        else printf("%lld/%lld\n",ans,G);
    }
    return 0;
}
View Code

 uva542 這題說的是給了一張表然每一個隊勝每一個隊的機率,每次都是兩個隊進行比賽,淘汰賽,最後計算每一個隊伍贏得比賽的機率按照他給的計算公式計算

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn = 16;
double map[maxn][maxn],ans[17][5];
char str[20][15];
int num[17],loca[17];
int main()
{
    for(int i = 0 ; i< 16 ; ++ i)
        scanf("%s",str[i]);
    for(int i = 0 ; i < 16 ; ++ i)
    for(int j = 0 ; j < 16 ; ++ j){
        scanf("%lf",&map[i][j]);
        map[i][j]/=100.0;
    }
    for(int i = 0 ; i < 16 ;  ++ i ) {num[i]=i; ans[i][0]=1.0;loca[i]=i;}
    for(int i =1 ; i <5 ; ++ i){
        for( int j = 0 ; j < 16 ;  ++ j){
            double t = 0.0;
            int y  = (1<<(i-1));
            int de = (j/y)&1?(j/y)-1:(j/y)+1;
            int st = de * y ;
            for( int k = st ; k/y == de ; ++k ){
                t += ans[k][i-1]*map[j][k];
            }
            ans[j][i]=t*ans[j][i-1];
        }
    }
    for(int i = 0 ; i< 16 ; ++ i)
        printf("%-10s p=%.2lf%c\n",str[i],ans[i][4]*100,'%');
    return 0;
}
View Code

 uva10277 這題說的是一我的他有一個抽屜的裏面有襪子,保證裏面最少2只,最多50000 只,給了一個機率就是拿獲得兩隻紅襪子的機率  進行 分析後假設總共 C只襪子 t只紅襪子 能夠獲得( t*(t-1)/(c*(c-1)))==P;而後枚舉每一個可能的值,二分區找可能獲得的紅襪子的 數量

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const long long  mod =1000;
typedef long long LL;
LL p,q;
LL gcd(LL a, LL b){
   return b==0?a:gcd(b,a%b);
}
int main()
{
    while(true){
        scanf("%lld%lld",&p,&q);
        if(p==0&&q==0) break;
        if((p==0)){
        printf("0 2\n");
           continue;
        }
        LL mid = 50000;
        LL t= gcd(p,q);
        p/=t;
        q/=t;
        if((q)>(mid*(mid-1))){
            printf("impossible\n");
            continue;
        }
        LL st=2;
        bool falg = false;
        for( ; st<=50000; ++ st){
            LL L=2 ,R = st;
            LL T = st*(st-1);
            if(T==0 || T%q != 0 ) continue;
            LL t = T/q;
            while(L<=R){
                mid  = L+(R-L)/2;
                LL E =mid*(mid-1);
                if(E%p==0&&(E/p == t)) {
                     falg= true; break;
                }
                if(E>(p*t))R=mid-1;
                else L= mid+1;
            }
            if(falg) break;
        }
       if(falg)
       printf("%lld %lld\n",mid,st-mid);
        else printf("impossible\n");
    }

     return 0;
}
View Code

 uva10169

題意:兩個罐子,A和B;

開始的時候A中1球、B中2球,但每一個罐子中都有一個紅球。

每次從兩個罐子分別中取出1個球。記錄結果真後放回,放回的同時向兩個罐子中分別增長1個白球

如此反覆操做。

問n次操做中,至少有1次取出的兩個球都是紅球的機率。 

若n次操做每次取出的球都是兩個紅球的機率小數點候有幾個連續的0。

而後計算 操做n次 算拿出大於等於1次 取出的 兩個都是紅球的機率 , 這個只要1 減去沒戲都沒有拿到 兩個都是紅球的的機率就好了 ,第二個是計算所有都是拿出紅球的機率在小數點後有多少個0 纔到除0外的數 針對這個機率 這樣 用log10 去處理一下 能夠知道 最後能夠化爲1/(1*2*2*3*3*4*4*5*5*6*6*7*7*8*9...n*(n+1)) 用log去保存(1*2*2*3*3*4*4*5*5*6*6*7*7*8*9...n*(n+1)) 由於log 10(1) = 0  因此獲得了一個 -(E.R)這樣一個數 (E)爲整數部分 (R) 爲小數部分 能夠知道 10^(-E) 是離小數點距離的E-1 然後面的 -0.R 不會產生與小數點相鄰的爲0 的數  由於 最小最小也比0.1大,兩個相乘恰好是E的距離因而用log 

#include <iostream>
#include <cstdio>
#include <string.h>
#include <cmath>
using namespace std;
double ans1[1000000];
int ans2[1000000];
int main()
{
     double t=0 ,ans=1;
     for(int i =1 ;i<1000000; ++ i){
         t+=log10(i)+log10(i+1);
         ans2[i] = int(t);
         double t2=(1.0/i)*(1.0/(i+1));
         ans*=(1-t2);
         ans1[i] = 1.0-ans;
     }
     int n;
     while(scanf("%d",&n)==1){
        printf("%.6lf %d\n",ans1[n],ans2[n]);
     }

    return 0;
}
View Code

 uva11181這題說的是一我的有,N個朋友 他們一塊兒去購物 每一個人會買東西的機率爲 p1,p2,p3,p4,p5...pN,當他們購物完後發現有 r我的買東西了 問每一個人買了東西  的機率 (N,r , p1 p2 p3 p4 .. pN 已知)(N<20)

 有貝葉斯公式能夠知道 P(Ai/B)=(P(Ai)*P(B/P(Ai)))/((P(Ai)*P(B/P(Ai))i從0到n-1),這裏能夠知道B爲選了r我的的機率 這個以題目例子爲例 買買不買+買不買買+不買買買。而後按照這個思路 P(AiB)=P(Ai)*P(B/P(Ai))也就獲得了 爲第i個買時 總共有r我的買了的機率 ,獲得答案 這裏主要是在完成了r我的的選擇上判斷第i我的在這r我的內的機率

#include <iostream>
#include <string.h>
#include <cstdio>
using namespace std;
double proba[20];
double ber[20],mu,ans[20];
int R[20],n,r;
void dfs(int ge,int lca,double P){
       if(lca == n && ge ==r ){
             mu+= P;
             for(int i = 0 ; i< r ;++ i)
                 ber[R[i]]+=P;
             return ;
       }
       if(((n-lca)<(r-ge))||(lca>=n)) return ;
       if(ge!=r){
            R[ge]=lca;
          dfs(ge+1,lca+1,P*proba[lca]);
       }
       dfs(ge,lca+1,P*(1-proba[lca]));
}
int main()
{
     int cas=0;
     while(true){

        scanf("%d%d",&n,&r);
        if(n==0&&r==0) break;
        mu =0.0;
        for(int i = 0 ; i < n ; ++ i )
             scanf("%lf",&proba[i]);
        memset(ber,0,sizeof(ber));
        dfs(0,0,1);
        printf("Case %d:\n",++cas);
        for(int i = 0 ; i<n ;++ i)
            printf("%.6lf\n",ber[i]/mu);
     }
    return 0;
}
View Code

 uva557 這題說的是給了N個孩子(N是偶數)  分給他們漢堡和牛肉餅,用扔硬幣的結果分配,正面是 分漢堡 反面是分牛肉餅 , 問最後兩我的不須要再扔硬幣的機率,剛開始我用正面的方法去解決 好睏難 , 後來想一想 用1減去要扔的機率 就獲得瞭解 ,  若是要礽那麼必定是這樣的 最後兩個 必定要是一個漢堡和一個牛肉餅, 這樣就獲得了前面的(n-2) 有(1/2  +   1/2 )^L 二項展開獲得 第 L/2+一、項  就是 前面 L個位置放 L/2 漢堡的機率  這樣 1- 這個機率 就 能夠了 , 用一下 遞推  而後 在來個log 保存位數 就ok了

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
double tow[50001*2];
double C[50001*2];
int main()
{
      tow[0]=0;
      for(int i = 1; i<=50001*2 ; ++ i ){
          tow[i]=tow[i-1]-log10(2);
      }
      C[2]=log10(2);
      for(int i = 4 , j = 2 ; i <=50001*2 ; i+=2,++j  )
      {
          C[ i ] = C[ i - 2 ] + log10(i)+log10(i-1) - log10(j) - log10(i-j);
      }
      int n;
      scanf("%d",&n);
      while(n--){
           int k;
           scanf("%d",&k);
           if(k<=2){
                printf("%.4lf\n",0.0);
                 continue;
           }
           k-=2;

           double A = C[k]+tow[k];
           A = pow(10.0,A);
           A=1-A;
           printf("%.4lf\n",A);
      }

    return 0;
}
View Code

 uva10900 一個玩家最初手裏有1元錢. 如今, 問他n個問題, 對於每一個問題他都有兩種選擇:1. 退出遊戲, 保持當前的錢數;
2. 回答問題, 若是答錯那麼錢數清0, 答對則錢數翻倍. 對於每一個問題, 玩家答對的機率都是一個t - 1範圍內的隨機數. 給出n, t, 求出最多可得到錢數的指望.先看看下面這段描述

Let's have n (n>0) questions left with a starting prize of a. We are going to compute f(n,a).

Suppose the probability of the correct answer to the first question is p (t<=p<=1). After

answering the question the prize changes to f(n-1,2*a) with probability p and to 0 with probability 1-p.

So the expected prize after this question is p*f(n-1,2*a)+(1-p)*0=p*f(n-1,2*a). If this prize is less than

a the player will choose not to answer and to quit the game keeping the prize of a. Therefore, getting a

question with probability of the correct answer equal to p the expected prize is max(a,p*f(n-1,2*a)).

  As the probability of the correct answer to the question is uniformly distributed over the range [t,1] the

average expected prize the player can quit with is 1/(t-1) * \int_t^1 max(a,p*f(n-1,2*a)) dp.
既然他要求的是最高的指望,p*f(k,r); 這句的意思是若是選擇了答下一題獲得的指望而 f(k,r)就是進入下一題所能獲得的指望,那好咱們先假設如今達到了第k個問題,那麼咱們就能夠知道在回答 第 k 個 問 題 的 時 候 所 能 得 到 的 期 望 是 多 少 對 於 不 同 的 p 會 得 到 不 同 的  結 果,解 釋 一 下   f(n-k,2^k) 表示剩下啊的 n-k 個問題所能取得的指望;那好如今討論一下這個p(機率)的問題 , 由均勻分佈能夠獲得,在區間上的機率是經過積分求得的,當獲得的k個問題的指望的時候 f(n-k,2^k)*p>2^(k-1) 的時候 咱們固然但願是繼續答題 然而當小於的時候咱們就不會繼續答題了而是就從住手,這樣咱們開始討論 題目中給的 t ,若是t 大於 p 那麼就能夠獲得必定能夠繼續下去 那麼天然在 第k個問題的時候獲得的機率就是 (t+1)/2*(fn-k,2^k); 可是當t小於p的時候咱們就在想應該將t-1 進行劃分 而後進行 一次積分  ∫ max(1<<(k-1) ,  f( n - k, 2 ^k ) * x ) dx|(從t到1) 而後獲得了咱們想要的

#include <iostream>
#include <cstdio>
#include <string.h>
#include <cmath>
using namespace std;
int main()
{
     int n ; double t;
     while(true){

        scanf("%d%lf",&n,&t);

        if(n == 0 && t == 0.0) break;
        double dp = 1<<n;
        for(int i= n-1 ;i >= 0 ; -- i ){
            double g = (1<<i);
            double a = g/dp;
            if(a<(t)) dp = (1+t)/2 * dp;
            else dp = ( (a - t)*g +dp*(1-a*a)/2 )/(1-t);
        }
        printf("%.3lf\n",dp);
     }
     return 0;
}
View Code

 uva10303 這題說的是給你了 n個點 能夠變成幾種不一樣的搜索二叉樹,經過枚舉左右孩子的個數 咱們能夠知道 F[n] += F[n-1-i]*F[i](0<=i<=n-1 ) 能夠發現是一個遞推的過程  是一個卡特蘭數 而後獲得 了卡特蘭數的 通向 Cn+1 =2(2*n+1) /(n+2)  *Cn;  模擬加上大數

 

#include <iostream>
#include <cstdio>
#include <string.h>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
const int maxn = 1005;
const int mod =10000;
vector<int> P;
stack<int>S;
class Bignumber{
    public : LL loc[200];
    public : int len;
    Bignumber(){
      memset(loc,0,sizeof(loc));
      len = 1;
    }
    Bignumber(vector<int> &A){
        int L =A.size();
        for(int i= 0 ; i<L/2 ; ++i){
            int temp =A[i];
            A[i]=A[L-1-i];
            A[L-1-i]=temp;
        }
        int t = A.size()/4 ;
        if(A.size()%4) t++;
        while(L<t*4){ A.push_back(0); L++ ;}
        len = 0;
        for(int i = 0 ; i<t*4 ;  i+=4)
            loc[len++]=A[i+3]*1000+A[i+2]*100+A[i+1]*10+A[i];
        while(len>1&&loc[len-1]==0){ len--; }
    }
   Bignumber operator *(int t){
          Bignumber ans;
          int temp = 0;
          for(int i = 0 ; i< len ;++ i){
                int r = loc[i]*t+temp;
                ans.loc[i]=r%mod;
                temp = r/mod;
             }
             ans.len=len;
             while(temp){
                ans.loc[ans.len++]=temp%mod;
                 temp/=mod;
             }
           return ans;
    }
    Bignumber operator /(int t){

          LL temp=0;
          for(int i = len-1; i >=0 ; -- i){
              temp=temp*mod+loc[i];
              int g = temp/t;
              temp%=t;
              P.push_back(g/1000);
              P.push_back((g%1000)/100);
              P.push_back((g%100)/10);
              P.push_back(g%10);
          }
         Bignumber ans=Bignumber(P);
         P.clear();
         return ans;
    }
    void output(){
       printf("%lld",loc[len-1]);
       for(int i = len-2 ; i>=0 ; -- i)
         printf("%04lld",loc[i]);
       printf("\n");
    }
};
Bignumber dp[maxn];
int main()
{
      //  freopen("out.txt","w",stdout);
      dp[0].loc[0] =1;
      dp[1].loc[0] = 1;
      for(int i = 1 ; i<1000; ++ i){
           dp[i+1]=dp[i]*((i*2+1)*2);
           dp[i+1]=dp[i+1]/(i+2);
     //     printf("i=%d %d\n",i,dp[i].len);
      }
      int n;
      while(scanf("%d",&n)==1){
       dp[n].output();
      }

     return 0;
}
View Code

 uva11176這題說的是給了一個賽季 一個隊伍要比賽n場每場贏得機率是 p 求 連勝的指望 LLL(0) LLW(1) LWL(1) WLL(1)WWL(2) WLW(1)WWL(2) WWW(3)

說說感覺吧 這題剛開始 我想用組合的方式解決這個問題可是在偶數個的判重的時候 不知道怎麼處理 一卡就卡了 2 天 , 而後發現時 用dp作 dp[i][j] 比i場連贏不超過 j場的機率 ,在考慮第 i場是輸仍是贏 仍是沒辦法解決那個重複的問題 最後看了解題報告 發現本身腦子略很差使  dp[i][j] 表示第i題 連勝不超過 j題的 機率  能夠想象 在求第 i 場是勝利仍是失敗的時候 能夠考慮dp[i][j] =dp[i-1][j] 就是在 dp[i-i][j] 的後面加上 L或者W 若是加L 那確定是沒有重複的若是加的是W 那麼得減去一種就是前i-1個的最後是 j個連續的W 這樣能夠獲得前 i-1最後的j個是連續的機率是 dp[i-2-j]*(1-p)*(p)^(j-1) 獲得了 第i-1個後面是 連續的j個W的機率 而後 dp[i][j]-=dp[i-2-j][j]*(1-p)*(p)^j 天然當 i-1==j 的時候發現這個是 i - 2 - j =-1 須要特判一下 能夠知道這個是 1 - p^n 而後獲得了這個點的機率

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn=505;
double dp[maxn][maxn];
double tp[maxn];
int main()
{
    int n;
    double p;
    while(scanf("%d%lf",&n,&p)==2&&n){
        for(int i = 0 ; i<=n ; ++ i)
             dp[0][i]=1;
        tp[0]=p;
        for(int i = 1 ; i <=n ;++i  )
            tp[i]=tp[i-1]*p;
        for(int i = 1 ; i<=n  ; ++ i)
        for(int j = 0 ; j<=n ; ++ j){
            dp[i][j]=dp[i-1][j];
            if(i-j-2>=0)
               dp[i][j]-=dp[i-j-2][j]*(1-p)*tp[j];
             else if( i-1 == j )
                dp[i][j]-=tp[j];
        }
        double ans=0;
        for(int i = n-1 ; i>= 0 ; -- i)
             ans+=(dp[n][i+1]-dp[n][i])*(i+1);
        printf("%.6lf\n",ans);
    }
    return 0;
}
View Code

 hdu 4828 度度熊最近很喜歡玩遊戲。這一天他在紙上畫了一個2行N列的長方形格子。他想把1到2N這些數依次放進去,可是爲了使格子看起來優美,他想找到使每行每列都遞增的方案。這題是一個鉤子公式 lrjP93黑書 而後咱們經過化簡 能夠獲得他與卡特蘭數 同樣的 遞推式這樣 咱們就剩下處理那個 模 的問題  A+k*mod /b=t%mod  咱們已知了 A mod 和 b 而後計算 出t A+mod*k == b*t --- t%=mod  b%=mod;  仍然獲得 b*t = A  ;  並不能經過直接除去獲得這個解 由於 他們是通過 了 mod 獲得的  如今化成 b*x =1  先求出 b關於mod的逆元x 而後 咱們根據 模運算 (a*b)%mod  == (a%mod *b%mod)%mod  能夠 獲得  ((b*x)*A)%mod == A 推出  (b*x*A)%mod ==A  而後就獲得了 t = (x*A)%mod; 這樣就求得了後一項

#include <iostream>
#include <cstdio>
#include <string.h>
#include <cmath>
using namespace std;
const long long mod = 1000000007;
typedef long long LL;
LL dp[1000005];
void gcd(LL a,LL b,LL &d,LL &x,LL &y){
     if(!b){
          d=a; x=1; y=0;
     }
     else {
        gcd(b,a%b,d,y,x); y-=x*(a/b);
     }
}
LL inv(LL a,LL n){
   LL d,x,y;
   gcd(a,n,d,x,y);
   return d==1?(x+n)%n:-1;
}
int main()
{
         LL p;
      dp[1]=1;
      for(int i =1 ; i <= 1000001 ; ++ i)
         {
               p=inv(i+2,mod);
             dp[i+1] = (2*(2*i+1)*dp[i])%mod;
             dp[i+1] = (p*dp[i+1])%mod;
         }
        int t;
      scanf("%d",&t);
      for(int cas = 1 ; cas <= t ; cas++){
        int n;
        scanf("%d",&n);
        printf("Case #%d:\n",cas);
        printf("%lld\n",dp[n]);
      }

      return 0;
}
View Code

 uva10518 這 題 說 的 是斐 波 那 契 求 值 得 過 程 中 的 調用了幾回 函數 F[0] =1 (調用了一次) F[1] =1 調用一次  F[2]調用了 3 次 獲得 F[n]=F[n-1]+F[n-2]+1 獲得了而後能夠知道 [  (1,1),(0,1) ] *[ f[n-2],f[n-2] ]  = [f[n],f[n-1]]  經過這個構造獲得了 【[111],[100],[001]】[f[n-1],f[n-2],1] 這樣一直下去 獲得了咱們想要的 而後矩陣快速冪一下

#include <iostream>
#include <cstdio>
#include <string.h>
#include <cmath>
using namespace std;
typedef long long LL;
int mod;
class Matrix{
    public: int M[3][3];
    public: Matrix(){
    }
    public: Matrix(int t){

    }
    Matrix operator *(const Matrix &A){
        Matrix ans;
        for(int i = 0 ; i<3 ; ++ i)
            for( int j = 0 ; j<3 ; ++ j){
              ans.M[i][j] = 0;
              for( int k = 0 ; k<3 ;++ k)
               ans.M[i][j]+=(M[i][k]*A.M[k][j]);
              ans.M[i][j]%=mod;
        }
        return ans;
    }
};

Matrix pow_t(LL n){
    Matrix A;
     A.M[2][2]=A.M[1][0]=A.M[0][0] =A.M[0][1]=A.M[0][2]=1;
     A.M[1][1]=A.M[1][2]=A.M[2][0] =A.M[2][1]=0;
    Matrix ans;
    ans.M[0][0]=ans.M[1][1]=ans.M[2][2]=1;
    ans.M[0][1]=ans.M[0][2]=ans.M[1][0]=ans.M[1][2]=ans.M[2][0]=ans.M[2][1]=0;
    while(n){
        if(n&1){
            ans = A*ans;
        }
        n>>=1;
        A=A*A;
    }
    return ans;
}
int main()
{
    LL n;
    int cas=0;
    while(true){
            scanf("%lld%d",&n,&mod);
            if( n == 0&& mod == 0 ) break;
        if(n<2){
            printf("Case %d: %lld %d %d\n",++cas,n,mod,1%mod);
           continue;
        }
        Matrix A = pow_t(n-1);
        printf("Case %d: %lld %d %d\n",++cas,n,mod,(A.M[0][0]+A.M[0][1]+A.M[0][2])%mod);
    }
    return 0;
}
View Code

 uva 10862 這 題 說 的 是 給 了 一 個 點 然 後 有 N 個 人家 每一個點只能跟他的左邊人家和右邊人家 或則從 中 心 節 點 獲 得 然 後 問 用 最 少 的 線使得這些點同通訊的方案總數

當最後的那個點不跟別的點聯通 是一種 跟 最後一個 一塊兒 最後3 4 5  6  這樣能夠獲得這樣的地推式 dp[n] =dp[n-1]*1+dp[n-2]*2+dp[n-3]*3+...+dp[0]*n 而後 化簡能夠獲得

dp[i]= dp[i-1] +S[i-1] ;S[i] =S[i-1] +dp[i];

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn = 2005;
const int mod = 100000;
struct Bignumber{
      int mart[255];
      int len;
      Bignumber(){
         len =1;
         memset(mart,0,sizeof(mart));
      }
      Bignumber operator +(const Bignumber &A){

             int L=max(len,A.len),temp=0;
             Bignumber ans;
             for(int i = 0; i<L; ++ i){
                 int r = mart[i]+A.mart[i]+temp;
                 ans.mart[i]=r%mod;
                 temp=r/mod;
             }
             ans.len = L;
             while(temp){
                ans.mart[ans.len++] =temp%mod;
                temp/=mod;
             }
             return ans;
      }
    Bignumber operator *(int T){
              Bignumber ans;
              int temp=0;
              for( int i =0; i<len ;++ i){
                  int r = mart[i]*T+temp;
                  ans.mart[i]=r%mod;
                  temp=r/mod;
              }
              ans.len=len;
              while(temp>0){
                  ans.mart[ans.len++] = temp%mod;
                  temp/=mod;
              }
              return ans;
    }
    void Output(){
         printf("%d",mart[len-1]);
         for(int i =len-2; i>=0; --i)
            printf("%05d",mart[i]);
         printf("\n");
    }
};
Bignumber dp[maxn];
Bignumber G[maxn];
int main()
{
     dp[0].mart[0]=dp[1].mart[0]=1;
     G[1].mart[0]=2;
     for(int i = 2; i<=2000 ; ++i){
         dp[i] = G[i-1]+dp[i-1];
         G[i]=G[i-1]+dp[i];
     }
     int n;
     while(true){
           scanf("%d",&n);
           if(n==0) break;
           dp[n].Output();
     }
    return 0;
}
View Code

 uva10334 這題說的是給了一塊兩個玻璃貼在一塊的東西 能夠 光在玻璃中穿過的方案總數有多少  咱們發現 中間的那個縫只能從邊界上來 ,可是旁邊的邊界能夠從 中間或者 旁邊了來   因而獲得了 dp[i][0] =dp[i-1][0]+dp[i-1][1] dp[i][1]=dp[i-1][0] 不斷的去推就獲得瞭解

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn = 2005;
const int mod = 100000;
struct Bignumber{
      int mart[255];
      int len;
      Bignumber(){
         len =1;
         memset(mart,0,sizeof(mart));
      }
      Bignumber operator +(const Bignumber &A){

             int L=max(len,A.len),temp=0;
             Bignumber ans;
             for(int i = 0; i<L; ++ i){
                 int r = mart[i]+A.mart[i]+temp;
                 ans.mart[i]=r%mod;
                 temp=r/mod;
             }
             ans.len = L;
             while(temp){
                ans.mart[ans.len++] =temp%mod;
                temp/=mod;
             }
             return ans;
      }
    Bignumber operator *(int T){
              Bignumber ans;
              int temp=0;
              for( int i =0; i<len ;++ i){
                  int r = mart[i]*T+temp;
                  ans.mart[i]=r%mod;
                  temp=r/mod;
              }
              ans.len=len;
              while(temp>0){
                  ans.mart[ans.len++] = temp%mod;
                  temp/=mod;
              }
              return ans;
    }
    void Output(){
         printf("%d",mart[len-1]);
         for(int i =len-2; i>=0; --i)
            printf("%05d",mart[i]);
         printf("\n");
    }
};
Bignumber dp[maxn][2];
Bignumber G[maxn];
int main()
{
     dp[0][0].mart[0]=1;
     G[0].mart[0]=1;
     for(int i = 1; i<=1000; ++i)
     {
        dp[i][0]=dp[i-1][0]+dp[i-1][1];
        dp[i][1]=dp[i-1][0];
        G[i]=dp[i][0]+dp[i][1];
     }
     int n;
     while(scanf("%d",&n)==1){
         G[n].Output();

     }
    return 0;
}
View Code

 uva10236這題求的是 斐波那契數列的中第n哥素數 這個素數的定義是這樣的 , 當前出現的fib[i] 不是前面的斐波那契的倍數除了1, 那麼這就是斐波那契素數,若是斐波那契數大於10^10 那麼只要輸出前9位就ok,好如今咱們要計算那麼不斷的用long double 去存數 一但出現大於10^10就 除以10 這樣獲得解 竟然能夠這樣作,之後遇處處理位數時能夠借鑑

#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
using namespace std;
const int maxn=1000005;
const int maxm=10000;
typedef long long ll;
bool vis[maxn];
int prime[maxn];
int fib[50],fibnum;
void init(){
   int num=0;
   memset(vis,false,sizeof(vis));
   for(ll i=2; i<1000000; ++i)
   if(vis[i]==false){
      prime[num++]=i;
      for(ll j=i*i; j<1000000; j+=i)
        vis[j]=true;
   }
   fibnum=4;
   fib[1]=fib[2]=1;
   for(int i=3; i<=50; ++i){
       fib[i]=fib[i-1]+fib[i-2];
   }
}
long double a[2][2],ans[2][2],c[2][2];
void solve(long double a[][2],long double b[][2]){
       memset(c,0,sizeof(c));
       for(int i=0; i<2; ++i)
         for(int j=0; j<2; ++j)
            for(int k=0; k<2; ++k)
              c[i][j]+= a[i][k]*b[k][j];
}
void equalop(long double a[][2],long double b[][2]){
      for(int i=0; i<2; ++i)
         for(int j=0; j<2; ++j)
           a[i][j]=b[i][j];
}
void pow_bin(int n){
      a[0][1]=a[0][0]=a[1][0]=1;
      a[1][1]=0;
      ans[0][0]=ans[1][1]=1 ; ans[0][1]=ans[1][0]=0;
      n=n-2;
      while(n){
          if( (n&1) != 0 ){
              solve(ans,a);
              equalop(ans,c);
          }
          n=n>>1;
          solve(a,a);
          equalop(a,c);
          while(a[0][0]>1000||ans[0][0]>10000){
             for(int i=0; i<2; ++i)
                 for(int j=0; j<2; ++j)
                   a[i][j]/=10,ans[i][j]/=10;
          }
      }
      long double a = ans[0][0]+ans[0][1];
      while(a<100000000) a*=10;
      int  as=(int)a;
      printf("%d\n",as);
}
int main()
{
    init();
    int n;
    while(scanf("%d",&n)==1){
          if(n<3){
             printf("%d\n",n==1?2:3);
          }else if(n<=14){
              printf("%d\n",fib[prime[n-1]]);
          }else{
              pow_bin(prime[n-1]);
           }

    }
    return 0;
}
View Code

 uva 10940 這題說的是給了一疊紙牌 從上到下 分別標號爲1 到n 而後你每次取最上方的兩張牌第一張扔掉第二張放在最底端 直到桌上只剩下一張牌爲止問這張牌的最初的編號,500000這麼多張 因爲數據太大模擬 不現實,那麼推推看有什麼規律發現,對於大於1的張數,能夠先一輪就是除去一半的張數,而後就獲得了剩下一半的張數 那麼咱們以前已經算出來了,這樣就直接在返回去找到以前的編號, 對於偶數張 有 dp[i]=dp[i/2]*2 奇數張有dp[i]=(dp[(i/2)+1]-1)*2, 對於偶數張沒什麼好解釋的 對於技術張, 由於最後會留下一張, 他是第二輪的第一張 那留下來的原先編號要往前在退一位

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn=500005;
int dp[maxn];
int main()
{
    dp[1]=1;
    for(int i=2; i<=500000; ++i){
          if(i%2==0){
              dp[i]=dp[i/2]*2;
          }else{
              dp[i]=(dp[(i/2)+1]-1)*2;
          }
    }
    int n;
    while(scanf("%d",&n)==1&&n!=0){
         printf("%d\n",dp[n]);

    }
    return 0;
}
View Code

uva10519

平面上有個圓,其中每兩個都相交於兩點,每三個都無公共點,它們將平面分紅塊區域,有,求f(n);

而後 假設有k+1 個圓, 第k+1 個圓與其餘k個圓有2k個交點, 那麼這個圓被分爲2*k 段弧,每段弧對應一塊區域那麼久多了2*k 塊區域 ,那麼 獲得f(k)=f(k-1)+2*(k-1);

那麼 f[1]=2;f[2]=4,f[3]=8; f[n]=f[n-1]+2*(n-1) ; f[2]-f[1]=2; f[3]-f[2]=4; ....f[n]-f[n-1]=2(n-1)  所有加起來, 就獲得了咱們要的解ok解決了

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
using namespace std;
const int maxn=1005;
struct bignumber{
   int v[maxn];
   int len;
   void clear(){
      memset(v,0,sizeof(v));
      len=1;
   }
   bignumber operator *(bignumber to){
      bignumber ans;
      ans.clear();
      for(int i=0; i<len; ++i)
      for(int j=0; j<to.len; ++j){
          ans.v[i+j]+=v[i]*to.v[j];
          ans.v[i+j+1]+=ans.v[i+j]/10;
          ans.v[i+j]%=10;
      }
       ans.len=max(len+to.len-1,1);
       for(int i=0; i<ans.len; ++i){
           ans.v[i+1]+=ans.v[i]/10;
           ans.v[i]%=10;
       }
       while(ans.v[ans.len]!=0){
         ans.v[ans.len+1]+=ans.v[ans.len]/10;
         ans.v[ans.len]%=10;
         ans.len++;
       }
       while(ans.len>1&&ans.v[ans.len-1]==0) ans.len--;
       return ans;
   }
   bignumber operator -(bignumber to){
       bignumber ans;
       ans.clear();
       ans.len=max(max(len,to.len),1);
       for(int i=0; i<ans.len; ++i)
        ans.v[i]=v[i]-to.v[i];
        for(int i=0; i<ans.len; ++i)
        if(ans.v[i]<0) {
             ans.v[i]+=10;
             ans.v[i+1]--;
        }
       while(ans.len>1&&ans.v[ans.len-1]==0) ans.len--;
       return ans;
   }
   bignumber operator +(int a){
       bignumber ans;
       ans.clear();
       ans.len=len;
       ans.v[0]=a;
       for(int i=0; i<ans.len; i++)
        ans.v[i]+=v[i];
       for(int i=0; i<ans.len; ++i){
         ans.v[i+1]+=ans.v[i]/10;
         ans.v[i]%=10;
       }
       ans.len++;
       while(ans.len>1&&ans.v[ans.len-1]==0) ans.len--;
       return ans;
   }
   void print(){
       for(int i=len-1; i>=0; --i)
         printf("%d",v[i]);
   }
};
char ss[200];
bignumber tobignumber(char *str){
    int len=strlen(str);
    reverse(str,str+len);
    bignumber ans;
    ans.clear();
    for(ans.len=len; ans.len>1; ans.len--){
         if(str[ans.len-1]!='0') break;
    }
    for(int i=ans.len-1; i>=0; --i){
         ans.v[i]=str[i]-'0';
    }
    return ans;
}
int main()
{
   while(scanf("%s",ss)==1){
      bignumber n;
      n=tobignumber(ss);
      if(n.len==1&&n.v[0]==0){
         puts("1"); continue;
      }
      bignumber ans;

      ans=n*n;
      ans=ans-n;
      ans=ans+2;
      ans.print();puts("");
   }
    return 0;
}
View Code

uva10918 這題說的是要畫

這樣的 3*n的圖 這是3*12的圖 ,而後計算有多少種方法 咱們知道長爲2 的有3 種 2 ,4 ,6.。。。的分別都有2種,計算最後畫這張圖有多少種方法

遞推

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
using namespace std;
int dp[50];
int main()
{
    memset(dp,0,sizeof(dp));
    dp[0]=1;
    for(int i=2; i<=30; ++i){
          if(i-2>=0) dp[i]+=dp[i-2]*3;
          for(int j=i-4; j>=0; j-=2)
             dp[i]+=dp[j]*2;
    }
    int n;
    while(scanf("%d",&n)==1&&n>=0){
        printf("%d\n",dp[n]);

    }

    return 0;
}
View Code

UVA11069這題挺有意思的能夠試試

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string.h>
using namespace std;
int dp[100][3];
int main()
{
    memset(dp,0,sizeof(dp));
    dp[1][0]=1;
    dp[1][1]=0;
    dp[1][2]=0;
    dp[2][0]=1;
    dp[2][1]=1;
    dp[2][2]=0;
    for(int i=3; i<=76; ++i){
         dp[i][0]=dp[i-1][1]+dp[i-1][2];
         dp[i][1]=dp[i-1][0];
         dp[i][2]=dp[i-2][0];
    }
    int n;
    while(scanf("%d",&n)==1){
         printf("%d\n",dp[n][0]+dp[n][1]);
    }
    return 0;
}
View Code

 uva10910 這題說的是給了N,T,P三個數分別是N個同窗T個分數每科及格分數爲P,且每一個同窗每科都及格,問最後N個同窗有多少分數狀況。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn=75;
int dp[maxn][maxn][maxn];
bool vis[maxn][maxn][maxn];
void dfs(int n,int t,int p){
      if(vis[n][t][p]) return ;
      if(n==0&&t==0){
         dp[n][t][p]=1;
         vis[n][t][p]=true;
         return ;
      }
      if(n==0&&t!=0){
         dp[n][t][p]=0;
         vis[n][t][p]=true;
         return ;
      }
      vis[n][t][p]=true;

      for(int i=p; ; ++i){
         if((t-i)<(n-1)*p) break;
         dfs(n-1,t-i,p);
         dp[n][t][p]+=dp[n-1][t-i][p];
      }
      return ;
}
int main()
{
    memset(vis,false,sizeof(vis));
    memset(dp,0,sizeof(dp));
    for(int i=1; i<=70; i++){
        for(int j=0; j<=70; ++j)
             for(int k=0; k<=70; ++k)
              dfs(i,j,k);
    }
    int N,P,T,cas;
    scanf("%d",&cas);
    for(int cc=1; cc<=cas; ++cc){
          scanf("%d%d%d",&N,&T,&P);
        printf("%d\n",dp[N][T][P]);
    }
    return 0;
}
View Code

 uva10328 這題說的是硬幣有正反兩面H和T而後 你扔硬幣 把全部狀況記錄下來, 問連續k個正面朝上的機率是多大我用 把當前連續 a個 的左邊和右邊分別放置一個T而後兩邊的H個數小於等於a 爲了不重複就把左邊的個數小於等於a 右邊的小於a 而後 用dp去作 dp[i][j] 表示i個骰子 連續j個H的個數, 

用cnt[i][j] 表示 i次投擲小於等於j個H的方案數,也就是dp[i][j]的 前j項和,枚舉連續a個的最右位置,而後用 dp[i][j]+=cnt[前面的個數-1][j]*cnt[後面的個數-1][j-1]{ 由於兩邊要放T因此都減一 特判 a個H 靠在 左右兩端的狀況,而後其餘狀況就用這樣的乘法去作} 

#include <iostream>
#include <cstdio>
#include<string.h>
#include <algorithm>
using namespace std;
const int mod =10000;
struct Bignumber{
    int v[20];
    int len;
    Bignumber(){
        len=1; memset(v,0,sizeof(v));
     }
    Bignumber operator +(Bignumber A){
        Bignumber ans;
        int s=0;
        ans.len=max(len,A.len);
        for(int i=0; i< ans.len; ++i){
             ans.v[i]=v[i]  + A.v[i] + s ;
             s=ans.v[i]/mod;
             ans.v[i]%=mod;
        }
        while(s){
             ans.v[ans.len]=s%mod;
             s/=mod;
             ++ans.len;
        }
        return ans;
    }
    Bignumber operator *(Bignumber A){
         Bignumber ans;
         for(int i=0; i<len; ++i){
             for(int j=0; j<A.len; j++){
                 ans.v[i+j]+=v[i]*A.v[j];
                 ans.v[i+j+1]+=ans.v[i+j]/mod;
                 ans.v[i+j] %= mod;
             }
         }
         ans.len=len+A.len-1;
         while(ans.v[ans.len]!=0){
             ans.v[ans.len+1]+=ans.v[ans.len]/mod;
             ans.v[ans.len]%=mod;
             ans.len++;
         }
         while(ans.len>1&&ans.v[ans.len-1]==0) ans.len--;
         return ans;
    }
    void print(){
        printf("%d",v[len-1]);
        for(int i=len-2; i>=0; --i)
             printf("%04d",v[i]);
    }
};
Bignumber dp[101][101];
Bignumber cnt[101][101];
int main()
{
    dp[0][0].v[0]=1;
    cnt[0][0].v[0]=cnt[0][1].v[0]=1;
    dp[1][0].v[0]=1; dp[1][1].v[0]=1;
    cnt[1][0].v[0]=1;cnt[1][1].v[0]=2;
    for(int i=2; i<=100; ++i) cnt[0][i].v[0]=1,cnt[1][i].v[0]=2;
    for( int i=2; i<=100; ++i ){
          cnt[i][0].v[0] = dp[i][0].v[0] = 1;
         for( int j=1; j<=i; ++j ){
             if( i - j > 0 )
                dp[i][j] = cnt[i-j-1][j-1] + cnt[i-j-1][j] ;
             else  dp[i][j].v[0]=1;

             for( int k=j+1; k <i ; k++ )
                 dp[ i ][ j ]=dp[i][j]+ (cnt[ k-j-1 ][ j ]*cnt[i-k-1][j-1]);
             cnt[i][j]=cnt[i][j-1]+dp[i][j];
         }
         for(int j=i+1; j<=100; j++)
             cnt[i][j]=cnt[i][j-1];
    }
     int n,k;
     while(scanf("%d%d",&n,&k)==2){
            Bignumber ans;
            for(int i=k; i<=n; ++i)
                ans=ans+dp[n][i];
            ans.print(); printf("\n");
     }
    return 0;
}
View Code

 uva10157 這題說的是 給了n對括號 , 而後要d 深度的 正確排列, 求出最後能夠有多少種排列方式, 咱們能夠考慮 第一個左括號和與他匹配的右括號,將這個序列分紅兩部分, 用dp[i][j]表示i對誇號造成 小於等於j的深度的方案總數,咱們第一分部分填 小於等於j-1層 外面填小於等於j層 那麼 兩個部分方案乘起來就是了 dp[i][j]= dp[i][j]+sum(d[i-k][j-1]*dp[i-k-1][j])

變成了 卡特蘭數了 。。。 

#include <iostream>
#include <cstdio>
#include<string.h>
#include <algorithm>
using namespace std;
const int mod =10000;
struct Bignumber{
    int v[50];
    int len;
    Bignumber(){
        len=1; memset(v,0,sizeof(v));
     }
    void clear(){
       len=1; memset(v,0,sizeof(v));
    }
    Bignumber operator +(Bignumber A){
        Bignumber ans;
        int s=0;
        ans.len=max(len,A.len);
        for(int i=0; i< ans.len; ++i){
             ans.v[i]=v[i]  + A.v[i] + s ;
             s=ans.v[i]/mod;
             ans.v[i]%=mod;
        }
        while(s){
             ans.v[ans.len]=s%mod;
             s/=mod;
             ++ans.len;
        }
        return ans;
    }
    Bignumber operator *(Bignumber A){
         Bignumber ans;
         for(int i=0; i<len; ++i){
             for(int j=0; j<A.len; j++){
                 ans.v[i+j]+=v[i]*A.v[j];
                 ans.v[i+j+1]+=ans.v[i+j]/mod;
                 ans.v[i+j] %= mod;
             }
         }
         ans.len=len+A.len-1;
         while(ans.v[ans.len]!=0){
             ans.v[ans.len+1]+=ans.v[ans.len]/mod;
             ans.v[ans.len]%=mod;
             ans.len++;
         }
         while(ans.len>1&&ans.v[ans.len-1]==0) ans.len--;
         return ans;
    }
    Bignumber operator - (Bignumber A){
         Bignumber ans;
         ans.len=max(len,A.len);
          for(int i=0; i<ans.len; ++i)
           ans.v[i]=v[i]-A.v[i];

           for(int i=0; i<ans.len; ++i)
             if(ans.v[i]<0) {
                    ans.v[i]+=mod;
                    ans.v[i+1]--;
             }

        while(ans.len>1&&ans.v[ans.len-1]==0){
             ans.len--;
        }

        return ans;
    }
    void print(){
        printf("%d",v[len-1]);
        for(int i=len-2; i>=0; --i)
             printf("%04d",v[i]);
    }
};
Bignumber dp[300][300];
int cmp(Bignumber A, Bignumber B){
    if(A.len!=B.len) return A.len>B.len?1:-1;
    for(int i=A.len-1; i>=0; --i)
         if(A.v[i]!=B.v[i] ) return A.v[i]>B.v[i]?1:-1;
     return 0;
}
int main()
{
     dp[0][0].len=1;
     for(int i=1; i<=150; ++i)
         dp[0][i].v[0] = dp[1][i].v[0] = 1;
     for(int i=2; i<=150; i++){
           dp[i][1].v[0]=1;
        for(int j=2; j<=i; ++j){
            for(int k=0; k<i; k++)
               dp[i][j]=dp[i][j]+( dp[ k ][ j-1 ] * dp[ i-k-1 ][ j ] );

        }
             for(int j=i+1; j<=150; ++j)
               dp[i][j]=dp[i][j-1];

     }
     int n,k;
     while(scanf("%d%d",&n,&k)==2){

                if( (n&1)!=0 || k*2>n){
                      puts("0"); continue;
                }
                Bignumber ans;
             ans= dp[n/2][k]-dp[n/2][k-1];
            ans.print(); printf("\n");
     }
    return 0;
}
View Code

 uva10128 這題說的是給了n我的每一個人都有不一樣的身高, 問從前日後看有p我的能夠看到,從後往前看有r我的能夠看到,用dp[n][p][r]表示有n我的從前日後看能夠看到p我的從後往前看能夠看到r我的, 那麼n+1我的放哪裏 , 假設來的這我的爲當前最矮,那麼他有三种放法, 第一放在最前面那麼能夠看到p+1我的, 放在最後面能夠看到r+1我的,還有就是放在中間,有n-1 個位置能夠放,

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn =15;
long long dp[maxn][maxn][maxn];
void inti(){
    memset(dp,0,sizeof(dp));
    dp[1][1][1]=1;
    for(int i=2; i<=13; ++i)
        for(int j=1; j<=i;  ++j )
          for(int k =1; k<=i; ++k )
            dp[i][j][k]=dp[i-1][j-1][k]+dp[i-1][j][k-1]+(i-2)*dp[i-1][j][k];
}
int main()
{
    inti();
    int n,p,r;
    int cas;
    scanf("%d",&cas);
    for(int cc=1; cc<=cas; ++cc){
        scanf("%d%d%d",&n,&p,&r);
         printf("%lld\n",dp[n][p][r]);

    }
    return 0;
}
View Code

 uva10081

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
double dp[105][10];
int main()
{
    int k,n;
    while(scanf("%d%d",&k,&n)==2){
        memset(dp,0,sizeof(dp));
        for(int i=0; i<=k; ++i){
             dp[1][i]=1.0/(k+1);
        }
        for(int i=2; i<=n; ++i){
             for(int j=0; j<=k; ++j){
                  double a = dp[i-1][j];
                  if(j-1>=0) a+=dp[i-1][j-1];
                  if(j+1<=k) a+=dp[i-1][j+1];
                  dp[i][j]=a/(k+1);
             }
        }
        double ans=0;
        for(int i=0; i<=k; ++i)
                     ans+=dp[n][i];
                     ans=ans*100;
        printf("%.5lf\n",ans);
    }
    return 0;
}
View Code

uva10943

/*
  dp[j][S] 表示 j個數拼成S的方案數
    dp[j][S]+=dp[j-1][S-t](0<=t<=S);
*/

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
using namespace std;
const int maxn=105;
const int mod=1000000;
int dp[maxn][maxn];
int main()
{
    dp[0][0]=1;
    for(int i=1; i<=100; ++i)
         for(int j=0; j<=100; ++j)
            for(int k=0; k<=j; ++k)
                 {
                     dp[i][j]+=dp[i-1][j-k];
                      dp[i][j]%=mod;
                 }
     int n,k;
     while(scanf("%d%d",&n,&k)==2){
          if(n==0&&k==0) break;
          printf("%d\n",dp[k][n]);

     }
    return 0;
}
View Code

uva10721

/*
       考慮第k堆放多少條,
       而後他會從前一堆的相應的條數而來
       dp[n][k][m]+=dp[n-t][k-1][m](t=1 ; t<=n && t<= m);
*/

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
using namespace std;
const int maxn = 55;
long long dp[maxn][maxn][maxn];
int main()
{
       int n,k,m;
      for(int i=1; i<=50; ++i){
           dp[0][0][i]=1;
           for(int j=1; j<=50; ++j)
              for(int k=1; k<=50; k++)
                for(int h=1; h<=i&&h<=k; ++h)
                   dp[k][j][i]+=dp[k-h][j-1][i];

      }
       while(scanf("%d%d%d",&n,&k,&m)==3){

           printf("%lld\n",dp[n][k][m]);
       }

      return 0;
}
View Code

uva10912

#include <iostream>
#include <algorithm>
#include <string.h>
#include <cstdio>
using namespace std;
long long dp[30][30][400];
bool vis[30][30][400];
long long dfs(int st, int L, int S){
         if(vis[st][L][S]) return dp[st][L][S];
         vis[st][L][S]=true;
         int ss =S-st;
         int LL=L-1;
         if( st<27 && LL == 0 && ss == 0 ){
             return dp[ st ][ L ][ S ] = 1 ;
         }
         if( st > 26 || ( LL==0 && ss!=0 ) || ( LL != 0 && ss == 0 ) || S < st ){
             return dp[st][L][S]=0;
         }
        for(int i=st+1; i<=26; ++i){
             if(ss-i<0) break;
             dp[st][L][S]+=dfs(i,LL,ss);
        }
        return dp[st][L][S];
}
int main()
{
    for(int i=1; i<=26; ++i)
         for(int j=1; j<=26; ++j)
           for(int k=i; k<400; ++k){
             dfs(i,j,k);
         }
         int L,S,cas=1;
         while(scanf("%d%d",&L,&S)==2){
                if(L==0&&S==0) break;
                printf("Case %d: ",cas++);
              if(L==0&&S==0) break;
              if(S>=400||L>26){
                 puts("0");
              }else{
               long long ans=0;
                for(int i=1; i<27; ++i)
                     ans+= dp[i][L][S];
                printf("%lld\n",ans);
            }
         }

    return 0;
}
View Code

uva10616

/*
     這題說的是給了n個數要求從中選出m個組成能被D整除
     的數。而後咱們能夠將他們先對D進行取餘操做,
     dp[j][m] 表示使用了j個數到達m這個值得方案總數

*/


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
using namespace std;
long long dp[205][205];
int data[205],r[205];
int main()
{
    int N,Q,cas=1;
    while(scanf("%d%d",&N,&Q)==2){
            if(N==0&&Q==0) break;
          for(int i=0; i<N; ++i)
             scanf("%d",&data[i]);
             printf("SET %d:\n",cas++);
          for(int i=0; i<Q; ++i){
              int M,D;
              scanf("%d%d",&D,&M);
              for(int j=0; j<N; ++j){
                    r[j]=((data[j]%D)+D)%D;
                }
              memset(dp,0,sizeof(dp));
              dp[0][0]=1;
              for(int y=0; y<N; ++y )
                 for(int j=M; j>=1; --j)
                   for(int k=200; k>=r[y]; --k)
                      dp[j][k]+=dp[j-1][k-r[y]];
              long long ans=0;
              for(int h=0; h<=200; h+=D)
                ans+=dp[M][h];
              printf("QUERY %d: %lld\n",i+1,ans);
          }

    }
    return 0;
}
View Code

 uva11125

/*
  狀態壓縮, 咱們經過將 四種顏色壓縮放在8進制中, 而後在壓4個4進制的值,
  由於每一個點和前面不同,前尾也不同,那麼咱們就枚舉尾部,而後而後第一個和他也要
  不同那麼咱們就把他初始化爲 pc pn (分別爲前面的顏色和個數) 而後咱們到最後的時候判斷是否
  已經沒有石頭了, 判斷fc fn pc pn 是否相等,  
*/

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
using namespace std;
int dp[2000000];
int A[5],b[5];
int dfs(int S){
     if(dp[S]!=-1) return dp[S];
     int fc,fn,pc,pn;
     int S1=S;
     pn=S1%4; S1/=4;
     pc=S1%4; S1/=4;
     fn=S1%4; S1/=4;
     fc=S1%4; S1/=4;
     int rr=0;
     for(int i=3; i>=0; --i){
         b[i]=S1%8;
         S1/=8;
         rr+=b[i];
     }
     if(rr==0){
         if(pc==fc&&pn==fn){
             return dp[S]=1;
         }else return dp[S]=0;
     }

     dp[S]=0;
     for(int i=0; i<4; ++i){
         if(pc==i)continue;
         for( int j=1; j<=b[i] && j<=3 ; ++j ){
             if(pn==j) continue;
             b[i]-=j;
             int S0=0;
             for(int h=0; h<4; ++h) S0=S0*8+b[h];
             S0= ( ( (S0*4+fc)*4+fn)*4+i )*4+j;
             dp[S]+=dfs(S0);
             b[i]+=j;
         }
     }
     return dp[S];
}
void sovle(){
    int n;
    scanf("%d",&n);
    int S=0;
    memset(A,0,sizeof(A));
    for(int i=0; i<n; ++i){
         scanf("%d",&A[i]);
         S+=A[i];
    }
    if(S==0){
         printf("1\n"); return ;
    }
    S=0;
    for(int i=0; i<4; ++i){
         S=S*8+A[i];
    }
    int ans=0;
    for(int i=0; i<4; ++i){
         for(int j=1; j<=A[i]&&j<=3; ++j){
              int t = ( ( ( S*4 + i ) * 4 + j ) * 4 + i )*4 + j;
              ans+=dfs(t);
         }
    }
    printf("%d\n",ans);
}
int main()
{
   int cas;
   scanf("%d",&cas);
    memset(dp,-1,sizeof(dp));
    for(int cc=1; cc<=cas; ++cc){
        sovle();
    }

    return 0;
}
View Code

uva10205

#include <iostream>
#include <cstdio>
#include<algorithm>
#include <string.h>
using namespace std;
struct card{
  char s1[10];
  char s2[15];
  int loc;
  bool operator < (const  card A)const{
     return loc<A.loc;
  }
}T[55],P[55];
char s1[15][10]={ "2" ,"3","4","5","6","7","8","9","10","Jack","Queen","King","Ace" };
char s2[5][15]={  "of Clubs","of Diamonds","of Hearts","of Spades" };
int turn[105][60];
void solve(int d){
   for(int i=1; i<=52; ++i){
        int  loc  = turn[d][i];
        P[loc].loc=i;
   }
   sort(P+1,P+53);
}
int main()
{
    int num=1;
    for(int i=0; i<4; ++i){
         for(int j=0; j<13; ++j){
             strcpy(T[num].s1,s1[j]);
             strcpy(T[num].s2,s2[i]);
             T[num].loc=num;
             num++;
         }
    }
    int cas;
    scanf("%d",&cas);
    for(int cc=0; cc<cas; ++cc){
            if(cc) printf("\n");
        for(int i=1; i<=52; ++i)
            P[i]=T[i];
        int n;
        scanf("%d",&n);
            for(int i=1; i<=n; ++i)
              for(int j=1; j<=52; ++j)
                  scanf("%d",&turn[i][j]);
        for(int i=0; i<n; ++i){
               int d;
               scanf("%d",&d);
               solve(d);
        }
        for(int i=1; i<=52; ++i)
             printf("%s %s\n",P[i].s1,P[i].s2);
    }
    return 0;
}
View Code

uva701

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string.h>
#include <cmath>
using namespace std;
long long v;
double Log(double a , double b){
   return log10(b)/log10(a);
}
int main()
{
    while(scanf("%I64d",&v)==1){
         int len=1;
         long long d=v;
         d/=10;
         while(d){
              d/=10; len++;
         }
         bool falg=false;
         for(int i = len+1 ; ; ++i ){
              double a,b;
             a=Log(2,v)+i*Log(2,10);
             b=Log(2,v+1)+i*Log(2,10);
             for(long long k = a; k<b; ++k){
                  if(k>=a&&k<=b){
                      cout<<k<<endl;
                     falg=true;break;
                  }
             }
             if(falg) break;
         }
    }
    return 0;
}
View Code

uva696

#include <stdio.h>

int n, m, ans;

int main() {
    while (~scanf("%d%d", &n, &m) && n + m) {
    if (n == 1) ans = m;
    else if (m == 1) ans = n;
    else if (n == 2) ans = m / 4 * 4 + ((m % 4 * 2) >= 4 ? 4 : (m % 4 * 2));
    else if (m == 2) ans = n / 4 * 4 + ((n % 4 * 2) >= 4 ? 4 : (n % 4 * 2));
    else ans = (m * n + 1) / 2;
    printf("%d knights may be placed on a %d row %d column board.\n", ans, n, m);
    }
    return 0;
}
View Code

uva254

/*
     這題說的是給了 n個 盤子的漢諾塔, 第
     m步, 3個棍子上的個數分別是多少,
     咱們每次肯定最大的那個會是在那個棍子上,
     咱們知道漢諾塔的 遞歸過程, 最簡的步數是2^n -1下 咱們利用這兩點,貪心的去作
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
using namespace std;
const int mod=10;
struct Bignumber{
    int v[100];
    int len;
    Bignumber(){
        memset(v,0,sizeof(v));
        len=1;
     }
    void clear(){
        memset(v,0,sizeof(v));
        len=1;
    }
    Bignumber operator *(int n){
        Bignumber ans;
        ans.len=len;
        int res=0;
        for(int i=0; i<ans.len; ++i){
            ans.v[i]=res+v[i]*n;
            res=ans.v[i]/mod;
            ans.v[i]%=mod;
        }
        while(res>0){
             ans.v[ans.len]=res%mod;
             ans.len++; res/=mod;
        }
        return ans;
    }
    Bignumber operator -( Bignumber A){
        Bignumber ans;
        ans.len=max(A.len,len);
        for(int i=0; i<ans.len; ++i)
             ans.v[i]=v[i]-A.v[i];
        for(int i=0; i<ans.len; ++i)
             if(ans.v[i]<0) ans.v[i]+=mod, ans.v[i+1]--;
        while(ans.len>1&&ans.v[ans.len-1]==0){
             ans.len--;
        }
        return ans;
    }
    Bignumber operator -( int a){
        Bignumber ans;
        ans.len=len;
        ans.v[0]=v[0]-a;
        for( int i = 1 ; i < ans.len ; ++ i )
             ans.v[i]=v[i];
        for(int i=0; i<ans.len; ++i)
             if(ans.v[i]<0) ans.v[i]+=mod, ans.v[i+1]--;
        while(ans.len>1&&ans.v[ans.len-1]==0){
             ans.len--;
        }
        return ans;
    }
    void print(){
        for(int i=len-1; i>=0; --i)
             printf("%d",v[i]);
    }
    bool operator < (Bignumber A){
        if( A.len!=len) return len<A.len;
        for(int i=len-1; i>=0 ;--i )
             if(v[i]!=A.v[i] ) return v[i]<A.v[i];
        return false;
    }
    bool operator <= (Bignumber A){
        if( A.len!=len) return len<A.len;
        for(int i=len-1; i>=0 ;--i )
             if(v[i]!=A.v[i] ) return v[i]<A.v[i];
        return true;
    }
}T[105];
int num[5];
char str[405];
Bignumber solve(){
    int len=strlen(str);
    Bignumber ans;
    ans.len=len;
    for(int i=len-1; i>=0; --i){
          ans.v[len-1-i]=str[i]-'0';
    }
    while(ans.len>1&&ans.v[ans.len-1]==0)
         ans.len--;
    return ans;
}
void dfs(int A,int B, int C, int leaf, Bignumber lest){
     if(lest.len==1&&lest.v[0]==0) {
            num[A]+=leaf;
            return;
     }
     for(int i=1; i<=leaf; ++i){
        if( lest <= T[i] && T[i-1] < lest ){
                num[A]+= leaf-i;
                Bignumber ans=( lest - T[i-1] ) -1;
             if(i&1){
                num[B]++;
                dfs(C,A,B,i-1,ans);
             }else{
                num[C]++;
                dfs(B,C,A,i-1,ans);
             }
            break;
        }
     }
}
int main()
{
   Bignumber a;
   a.v[0]=1;
    for(int i=1; i<101; ++i){
         a=a*2;

         T[i]=a-1;
    }
    int n;
    while(scanf("%d%s",&n,str)==2){
         Bignumber ans=solve();
         if(n==0&&ans.len==1&&ans.v[0]==0) break;
         memset(num,0,sizeof(num));
         dfs(0,1,2,n,ans);
         printf("%d %d %d\n",num[0],num[1],num[2]);
    }
    return 0;
}
View Code

uva10994

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int solve(int v){

   while(true){
       if(v==0) return 0;
       if(v%10) return v%10;
       v/=10;
   }
}
int W[100];
long long H[]={0,1,3,6,10,15,21,28,36,45};
long long cnt(long long  R){
     int len=1;
     W[0]=R%10;R/=10;
     while(R){
         W[len++]=R%10;R/=10;
     }
     for(int i=0; i<len/2; ++i){
         int t=W[i];
         W[i]=W[len-1-i];
         W[len-1-i]=t;
     }
     long long ans=0;
     long long num=0;
     for(int i=0; i<len; ++i){
        ans+= num * (45LL) + H[ W[i] ];
        num=num*10+W[i];
     }
     return ans;
}
int main()
{
    long long p,q;
    while(scanf("%lld%lld",&p,&q)==2){
            if(p<0||q<0) break;
       long long  ans1=0,ans2=0;
       long long R=solve(p);
       ans1=cnt(p);
       ans2=cnt(q);
       printf("%lld\n",ans2-ans1+R);
    }
    return 0;
}
View Code

uva10570

/*
   枚舉每個1可能的位置
*/

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
using namespace std;
const int maxn=5050;
int F[maxn];
int t[maxn];
int tr[maxn];
int solve(int r[], int n){
    for(int i=0; i<n; ++i){
            t[i]=r[i];
            tr[t[i]]=i;
    }
     int v=0;
     int ans=0;
    for(int i=0; i<n; ++i){
        v=(v+1)%n;
         if(t[i]!=v){
              ans++;
              int trr=tr[v];
              t[ trr ] = t[ i ];
              tr[ t[i] ] = trr;
              t[i]=v;
              tr[v]=i;
         }
    }
    return ans;
}
int main()
{
    int n;
    while(true){
         scanf("%d",&n);
         if(n<=2) break;
         int ans=100000;
         for(int i=0; i<n; ++i){
             scanf("%d",&F[i]);
             F[i]--;
             F[i+n]=F[i];
         }

         for(int i=0; i<n; ++i){
               ans=min( ans , solve(F+i,n) ) ;
         }
         for(int i=0; i<n/2; ++i){
             int t = F[i];
             F[i]=F[n-i-1];
             F[n-i-1]=t;
             t=F[i+n];
             F[i+n]=F[n+n-i-1];
             F[n+n-i-1]=t;
         }
         for(int i=0; i<n; ++i){
               ans=min( ans , solve(F+i,n) ) ;
         }
         printf("%d\n",ans);
    }

    return 0;
}
View Code
相關文章
相關標籤/搜索