大大出的題java
大大常常吐槽沒有人補,因此我決定作一個ios
A. APA of Orz Pandaside
題意:給你一個包含+-*/%和()的表達式,讓你把它轉化成java裏BigInteger的形式函數
大概就像這樣 "a.add(b).remainder(M).multiply(d.substract(e.multiply(f)).add(g.divide(h))).multiply (BigInteger.ValueOf(233)) ... ..."spa
輸入的串長度<=10003d
有意思的模擬題,不是很好寫code
首先要看清題,a+(b+c)應該輸出爲a.add(b.add(c))而不是a.add(b).add(c)對象
我以前看錯題,使得這個題難度高了一點,可是那樣也能夠作,只需預處理無用括號便可blog
觀察能夠發現,不存在(a.add(b)).add(c)這種說法,也就是說,括號的本質做用是改變運算順序,而後把括號裏的表達式做爲一個對象參與運算排序
那麼就能夠把括號裏的東西當作一個變量,而後問題就轉化爲沒有括號的表達式的處理
對於括號中的括號,能夠把輸出寫成參數l和r的函數,功能爲輸出下標爲[l,r]的子區間,而後遞歸處理
接下來的問題是找到輸出序列中括號的包含範圍,例如a+b*c要表示爲a.add(b.multiply(c)),如何找到add右括號的位置
能夠開一個棧
左括號能夠直接壓入
當壓入右括號時,能夠把左右括號中的全部運算符,包括括號所有湮滅
當壓入+-時,能夠把全部棧頭的運算符湮滅,並令其右括號的位置在此運算符以前,但應在遇到左括號時中止
當壓入*/%時,能夠把棧頭的*/%運算符湮滅,並令其右括號的位置在此運算符以前,但應遇到左括號或+-爲止
代碼:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 char fc[5][10]={ 8 {'a','d','d',0}, 9 {'s','u','b','s','t','r','a','c','t',0}, 10 {'m','u','l','t','i','p','l','y',0}, 11 {'d','i','v','i','d','e',0}, 12 {'r','e','m','a','i','n','d','e','r',0} 13 }; 14 int fs[256]; 15 char s[11000]; int n; 16 char q[11000]; int p[11000],hd=0; 17 bool flg[11000]; 18 int nxt[11000]; 19 bool chck(char x){ return x=='+'||x=='-'||x=='*'||x=='/'||x=='%'||x=='('||x==')';} 20 bool chck1(char x){ return x=='+'||x=='-'||!x;} 21 bool chck2(char x){ return x=='*'||x=='/'||x=='%'||!x;} 22 void ot(int x,int y){ 23 for(int i=x;i<=y;++i)if(s[i] && s[i]!='(' && s[i]!=')'){ 24 if(!chck(s[i])) printf("%c",s[i]); 25 else{ 26 printf("."); 27 for(int j=0;fc[fs[(int)s[i]]][j];++j) printf("%c",fc[fs[(int)s[i]]][j]); 28 printf("("); ot(i+1,nxt[i]); printf(")"); 29 i=nxt[i]; 30 } 31 } 32 } 33 void prvs(){ 34 fs['+']=0,fs['-']=1,fs['*']=2,fs['/']=3,fs['%']=4; 35 hd=0; 36 for(int i=1;i<=n;++i) flg[i]=false; 37 s[0]=0,s[n+1]=0; 38 for(int i=1;i<=n;++i) nxt[i]=0; 39 } 40 int main(){ 41 //freopen("ddd.in","r",stdin); 42 while(scanf("%s",s+1)!=EOF){ 43 n=strlen(s+1); prvs(); 44 for(int i=1;i<=n;++i)if(chck(s[i])){ 45 if(s[i]==')'){ 46 bool mk1=false,mk2=false; 47 for(;q[hd]!='(';--hd){ 48 if(q[hd]=='+'||q[hd]=='-') mk1=true; 49 if(q[hd]=='*'||q[hd]=='/'||q[hd]=='%') mk2=true; 50 } 51 if((chck2(s[i+1])||chck2(s[p[hd]-1])) && !mk1){ 52 if(!mk2) flg[i]=true,flg[p[hd]]=true; 53 if(s[p[hd]-1]!='/'&&s[p[hd]-1]!='%') flg[i]=true,flg[p[hd]]=true; 54 } 55 if(s[i+1]==')' && s[p[hd]-1]=='(') 56 flg[i]=true,flg[p[hd]]=true; 57 if(chck1(s[i+1]) && chck1(s[p[hd]-1])) 58 flg[i]=true,flg[p[hd]]=true; 59 nxt[p[hd]]=i; 60 --hd; 61 } 62 else q[++hd]=s[i]; p[hd]=i; 63 } 64 hd=0; 65 for(int i=1;i<=n;++i){ 66 //if(flg[i]) s[i]=0; 67 if(s[i] && chck(s[i])){ 68 if(s[i]=='(') q[++hd]=s[i],p[hd]=i; 69 if(s[i]==')'){ 70 for(;q[hd]!='(';--hd) nxt[p[hd]]=i-1; 71 --hd; 72 } 73 if(chck1(s[i])){ 74 for(;hd && q[hd]!='(';--hd) nxt[p[hd]]=i-1; 75 q[++hd]=s[i],p[hd]=i; 76 } 77 if(chck2(s[i])){ 78 for(;hd && q[hd]!='(' && !chck1(q[hd]);--hd) nxt[p[hd]]=i-1; 79 q[++hd]=s[i],p[hd]=i; 80 } 81 } 82 } 83 for(;hd;--hd) nxt[p[hd]]=n; 84 /*for(int i=1;i<=n;++i) cout<<i<<" "; 85 cout<<endl; 86 for(int i=1;i<=n;++i) cout<<s[i]<<" "; 87 cout<<endl; 88 for(int i=1;i<=n;++i) cout<<nxt[i]<<" "; 89 cout<<endl;*/ 90 ot(1,n); printf("\n"); 91 } 92 return 0; 93 } 94 95
B. Brute Force of Orz Pandas
題意:
給你一個輸出n層漢諾塔最優解的詳細步驟的程序
輸入n和k,要求你輸入當此程序輸入爲n時的第k行輸入,若是k大於總行數則輸出Orz
n,k<=10^18
最開始的思路時數學/推公式/找規律解決,這樣其實比較難搞
咱們發現,直接運行給出的程序不可行是由於給出的程序會遍歷每一種狀況,而若是咱們發現調用某個遞歸函數致使的輸出大於當前查詢的行數,徹底能夠跳過它
而對於每一個遞歸的輸出行數,能夠由公式快速獲得
那麼相似在平衡樹上查找第k大的方式
對於每一層,若是k小於第一個遞歸將輸出的行數,那麼進第一個遞歸,遞歸解決問題
若是等於第一個遞歸輸出行數+1,說明找到咱們的答案
若是大於第一個遞歸輸出行數+1,就令k-=第一個遞歸輸出行數+1,而後進第二個遞歸
對於n很大的狀況,因爲k不大,全部只有當函數中的size很小的時候纔有可能涉及到中間的printf和第二個遞歸
那麼能夠預處理出最大的知足第一個遞歸輸出行數>=所求行數的size,而後從這裏開始遞歸便可
代碼:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 #define LL long long 8 LL n,m; 9 LL pw2[63]; 10 void gkd(int x,char l,char md,char r){ 11 if(pw2[x-1]-1>=m) gkd(x-1,l,r,md); 12 else if(pw2[x-1]-1==m-1) 13 printf("move %d from %c to %c\n",x,l,md); 14 else{ 15 m-=pw2[x-1]; 16 gkd(x-1,r,md,l); 17 } 18 } 19 int main(){ 20 //freopen("ddd.in","r",stdin); 21 pw2[0]=1; 22 for(int i=1;i<63;++i) pw2[i]=pw2[i-1]*2; 23 while(scanf("%lld%lld",&n,&m)!=EOF){ 24 char l='A',md='B',r='C'; 25 int tmp=1; 26 for(;pw2[tmp]<=m;++tmp); 27 if((n-tmp)&1) swap(md,r); 28 if(n<=60 && m>pw2[n]-1) printf("Orz\n"); 29 //注意n 30 else gkd(tmp,l,md,r); 31 } 32 return 0; 33 } 34 35
D. Director of Orz Pandas
題意:
給你兩組物品,數量分別爲n和m,每一個物品有一個價值,還有k對關係,表示選了第一組的i物品就不能選第二組的j物品
如今問你能夠取到的最大價值是多少
n,m<=100,k<=10000
能夠把問題轉化爲先所有都選,而後剔除某些物品使得知足題目要求
裸的最小點權獨立集,建圖跑dinic便可,最壞複雜度O(n^2m)T不了
源到第一組的全部物品連邊,權值爲物品價值,第二組的全部物品到匯連邊,權值爲物品價值,衝突物品之間連無窮權值
鴿掉源或匯的一條邊就表示剔除某個物品,只要有兩個衝突的物品沒被鴿掉就存在從源到匯的路徑
因此最小鴿就是答案
代碼:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 int rd(){int z=0,mk=1; char ch=getchar(); 8 while(ch<'0'||ch>'9'){if(ch=='-')mk=-1; ch=getchar();} 9 while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0'; ch=getchar();} 10 return z*mk; 11 } 12 const int oo=1000000007; 13 struct edg{int y,nxt,v;}e[41000]; int lk[210],ltp=1; 14 void ist(int x,int y,int v){ 15 e[++ltp]=(edg){y,lk[x],v}; lk[x]=ltp; 16 e[++ltp]=(edg){x,lk[y],0}; lk[y]=ltp; 17 } 18 int n,m,o,a[210]; int s,t; 19 int lvl[210]; 20 int q[210],hd=0; 21 int crt[210]; 22 bool gtlvl(){ 23 for(int i=s;i<=t;++i) lvl[i]=0; 24 lvl[(q[(hd=1)]=s)]=1; 25 for(int k=1;k<=hd;++k){ 26 crt[q[k]]=lk[q[k]]; 27 for(int i=lk[q[k]];i;i=e[i].nxt)if(e[i].v && !lvl[e[i].y]){ 28 lvl[e[i].y]=lvl[q[k]]+1; 29 q[++hd]=e[i].y; 30 } 31 } 32 return lvl[t]; 33 } 34 int mxflw(int x,int y){ 35 if(x==t) return y; 36 int bwl=0,flw=0; 37 for(int i=crt[x];i && bwl<y;i=e[i].nxt)if(lvl[e[i].y]==lvl[x]+1 && e[i].v) 38 if((flw=mxflw(e[i].y,min(e[i].v,y-bwl)))){ 39 e[i].v-=flw,e[i^1].v+=flw; 40 //cout<<e[i^1].y<<"->"<<e[i].y<<" "<<flw<<endl; 41 bwl+=flw; 42 if(!e[i].v) crt[x]=e[i].nxt; 43 } 44 if(!bwl) lvl[x]=0; 45 return bwl; 46 } 47 int dnc(){ 48 int bwl=0,flw=0; 49 while(gtlvl())while((flw=mxflw(s,oo))){ 50 bwl+=flw; 51 //printf("%d %d\n",bwl,flw); 52 } 53 return bwl; 54 } 55 void prvs(){ 56 ltp=1; 57 for(int i=0;i<=n+m+1;++i) lk[i]=0; 58 } 59 int main(){ 60 //freopen("ddd.in","r",stdin); 61 while(scanf("%d%d",&n,&m)!=EOF){ 62 prvs(); s=0,t=n+m+1; 63 int sm=0; 64 for(int i=1;i<=n;++i){ 65 a[i]=rd(); 66 sm+=a[i]; 67 ist(s,i,a[i]); 68 } 69 for(int i=n+1;i<=n+m;++i){ 70 a[i]=rd(); 71 sm+=a[i]; 72 ist(i,t,a[i]); 73 } 74 o=rd(); 75 int l,r; 76 while(o --> 0){ 77 l=rd(),r=rd(); 78 if(l>r) swap(l,r); 79 ist(l,r,oo); 80 } 81 printf("%d\n",sm-dnc()); 82 /*for(int i=s;i<=t;++i){ 83 cout<<i<<":"<<endl; 84 for(int j=lk[i];j;j=e[j].nxt) printf("%d %d\n",e[j].y,e[j].v); 85 }*/ 86 } 87 return 0; 88 } 89 90
H. Horton and Orz Pandas
題意:
給你一個n個點m條邊的無向圖,每條邊都有兩個權值a和b,如今問你在全部的包含全部點的聯通子圖中,a權值的和除以b權值的和的最大值是多少
n<=1000,m<=1e7
給a/b排序,而後Kruskal求最小生成樹是錯的
緣由一,儘管有c/d<(a+c)/(b+d)<a/b當c/d<a/b的結論,可是
這也是最優比率生成樹不能直接排序作的緣由
緣由二,答案不是最優比率生成樹(即a權值的和除以b權值的和最大的生成樹)
由於c/d<(a+c)/(b+d)<a/b,因此若是有樹邊的比率小於答案,那麼把這條邊加入是可讓答案增長的,而題中並無規定必定要求生成樹
本題實質上是求包含全部點的最大密度子圖,是經典的01分數規劃問題
令原圖爲S,λ=a(x)/b(x),其中a(x)表示子圖x的a權之和,λ*=a(x*)/b(x*)爲λ的最優值,則有0=a(x*)-λb(x*)
不妨設g(λ)=max{x⊆S | a(x)-λb(x)},則g(λ)是單調遞減函數
證實:
對於λ1>λ2,g(λ1)=a(x1)-λ1b(x1) < a(x1)-λ2b(x1) (b(x)>0),而x1未必是λ2的最優解,即g(λ2)>=a(x1)-λ2b(x1)
故g(λ1)<=g(λ2)
又能夠發現g(λ*)=0
證實:
若g(λ)=max{x⊆S | a(x)-λ*b(x)}>0,即∃x1使a(x1)-λ*b(x1)>0,則有λ*<a(x1)/b(x1),與λ*的定義不符
而根據定義,,∃x*使a(x1)-λ*b(x1)=0,故g(λ*)=0
那麼只需二分答案,而後根據二分的答案構造新的邊權a-bλ
此時原來的分數規劃問題就轉化爲線性的問題,能夠直接用Kruskal求最大生成樹獲得最優比率生成樹
本題要求求包含全部點的最大密度子圖
那麼能夠考慮對於只有一個邊權的包含全部點的最大權值子圖如何求
顯然只需在最大生成樹的基礎上,把全部非負邊權加入便可
那麼對於構造出來的新邊權作如上處理,檢查答案是否大於零
本題注意:
1.浮點數二分不能(l+eps<r),會由於精度問題死循環,而應該計算好循環次數後直接for
2.由於sort次數不少,而結構體sort可能很慢,因此能夠把結構體sort的比較函數的參數寫成傳地址形式,即參數名前加'&',或者手寫排序
代碼:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<time.h> 7 using namespace std; 8 const double eps=1e-9; 9 int rd(){int z=0,mk=1; char ch=getchar(); 10 while(ch<'0'||ch>'9'){if(ch=='-') mk=-1; ch=getchar();} 11 while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0'; ch=getchar();} 12 return z*mk; 13 } 14 struct nds{int x,y,a,b; double c;}b[110000]; 15 int n,m; 16 int tp[11000]; 17 int gttp(int x){ 18 int y=x,tmp; 19 while(tp[y]!=y) y=tp[y]; 20 while(x!=y){ 21 tmp=tp[x]; 22 tp[x]=y; 23 x=tmp; 24 } 25 return y; 26 } 27 inline void mg(int x,int y){ tp[gttp(x)]=gttp(y);} 28 //用於求最優比率生成樹的二分上下界 29 double gtmn(){ 30 for(int i=1;i<=n;++i) tp[i]=i; 31 double aa=0,ab=0; 32 for(int i=1;i<=m;++i)if(gttp(b[i].x)!=gttp(b[i].y)){ 33 mg(b[i].x,b[i].y); 34 aa+=b[i].a,ab+=b[i].b; 35 } 36 return ab/aa; 37 } 38 //bool cmp1(nds x,nds y){ return x.a<y.a;} 39 //bool cmp2(nds x,nds y){ return x.b>y.b;} 40 double gtmx(){ 41 double aa=0,ab=0; 42 /*sort(b+1,b+m+1,cmp1); 43 for(int i=1;i<n;++i) aa+=b[i].a; 44 sort(b+1,b+m+1,cmp2);*/ 45 for(int i=1;i<n;++i) ab+=b[i].b; 46 //return ab/aa; 47 return ab; 48 } 49 int s; //用於檢查運行時間 50 //手寫堆排序 51 nds a[110000]; 52 void st(){ 53 for(int i=1;i<=m;++i) 54 for(int j=i;j>1 && b[j].c<b[j>>1].c;j>>=1) swap(b[j],b[j>>1]); 55 int sz=m; 56 for(int i=1;i<=m;++i){ 57 a[i]=b[1]; 58 swap(b[1],b[sz--]); 59 for(int j=1;j<=sz;){ 60 int k=j; 61 if((j<<1)<=sz && b[j<<1].c<b[k].c) k=(j<<1); 62 if((j<<1|1)<=sz && b[j<<1|1].c<b[k].c) k=(j<<1|1); 63 if(k==j) break; 64 swap(b[j],b[k]); 65 j=k; 66 } 67 } 68 for(int i=1;i<=m;++i) b[i]=a[i]; 69 } 70 bool cmp(nds &x,nds &y){ return x.c<y.c;} //使結構體sort加速 71 bool chck(double x){ 72 for(int i=1;i<=m;++i) b[i].c=b[i].b-x*b[i].a; 73 sort(b+1,b+m+1,cmp); 74 //st(); 75 //cout<<clock()-s<<endl; 76 //s=clock(); 77 double bwl=0; 78 for(int i=1;i<=n;++i) tp[i]=i; 79 for(int i=m;i>=1;--i){ 80 if(gttp(b[i].x)!=gttp(b[i].y)){ 81 mg(b[i].x,b[i].y); 82 bwl+=b[i].c; 83 } 84 else if(b[i].c>0) bwl+=b[i].c; 85 } 86 //cout<<clock()-s<<endl; 87 //s=clock(); 88 return bwl>0; 89 } 90 double bnrsch(){ 91 double l=gtmn(),r=gtmx(),md; 92 //while(l+eps<r){ 注意浮點數二分的寫法 93 int tmp=(log(r-l+1)+10*log(10))/log(2); 94 for(int i=1;i<=tmp;++i){ 95 md=(l+r)/2; 96 (chck(md) ? l : r)=md; 97 //cout<<i<<" "<<clock()-s<<endl; 98 } 99 return chck(r) ? r : l; 100 } 101 int main(){ 102 //freopen("ddd.in","r",stdin); 103 //s=clock(); 104 while(scanf("%d%d",&n,&m)!=EOF){ 105 for(int i=1;i<=m;++i) b[i].x=rd(),b[i].y=rd(),b[i].a=rd(),b[i].b=rd(); 106 printf("%.10lf\n",bnrsch()); 107 } 108 //cout<<clock()-s<<endl; 109 return 0; 110 }