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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
化簡後能夠發現是一個等比數列 由於(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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }