hdu刷题2
hdu1021
給n,看費波納列數能否被3整除
算是找規律吧,以后碰到這種題就打打表找找規律吧
#include <stdio.h> int main(void) { int n; while(scanf("%d", &n) != EOF) { if(n%8==2 || n%8==6) printf("yes\n"); else printf("no\n"); } return 0; } View Code?
hdu1022 棧的簡單利用吧
給兩個隊列 ?看第一個隊列是否可以用第二個隊列的方式出去
#include<iostream> #include<string.h> #include<stdio.h> #include<stack> using namespace std; int main() {char s1[100],s2[100];int n,j,k,f[100];stack<char>s;while(cin>>n>>s1>>s2){while(!s.empty())s.pop();memset(f,-1,sizeof(f));j=k=0;for(int i=0;i<n;i++){s.push(s1[i]);f[k++]=1;while(!s.empty()&&s.top()==s2[j]){f[k++]=0;s.pop();j++;}}if(j==n){cout<<"Yes."<<endl;for(int i=0;i<k;i++){if(f[i]) cout<<"in"<<endl;else cout<<"out"<<endl;}}else cout<<"No."<<endl;printf("FINISH\n");}return 0; } View Code?
hdu1023 ?什么什么卡特蘭數。。。
這個還是卡特蘭數+大數
https://blog.csdn.net/wu_tongtong/article/details/78161211
卡特蘭數規律
令h(0)=1,h(1)=1,catalan數滿足遞推式?[2h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)*h(0) (n>=2) h(n)=C(2n,n)/(n+1) (n=0,1,2,...)
?
#include<iostream> #include<cstdio> #include<cstring>using namespace std;int a[110][110]; //大數卡特蘭數 int b[110]; //卡特蘭數的長度 void Catalan(){ //求卡特蘭數int i,j,len,carry,tmp;a[1][0]=b[1]=1;len=1;for(i=2;i<=100;i++){for(j=0;j<len;j++) //乘法 a[i][j]=a[i-1][j]*(4*i-2);carry=0;for(j=0;j<len;j++){ //處理相乘結果tmp=carry+a[i][j];a[i][j]=tmp%10;carry=tmp/10;}while(carry){ //進位處理 a[i][len++]=carry%10;carry/=10;}//carry=0;for(j=len-1;j>=0;j--){ //除法 tmp=carry*10+a[i][j];a[i][j]=tmp/(i+1);carry=tmp%(i+1);} while(!a[i][len-1]) //高位零處理len--;b[i]=len;} }int main(){//freopen("input.txt","r",stdin);int n;Catalan();while(~scanf("%d",&n)){for(int i=b[n]-1;i>=0;i--)printf("%d",a[n][i]);printf("\n");}return 0; } View Code?
?
hdu1024
又是dp。。。難得一匹,給n個數,你可以劃分m個區間,求這些區間的最大值。二維的dp還不行,還要利用滾動數組降維
https://blog.csdn.net/pmt123456/article/details/52695470 這個解釋還是比較好的
這題給我的啟發:dp找方程時,一定要弄清楚會有幾個不同的狀態,可以事先手動模擬一下。
比如這題,先是有兩個變化的數n和m,那么我就想dp[i][j],有i個區間j個數的最大值。對于ai來數,我就要想到,ai會和哪些dp(上一個)聯系起來
這個數我可以把它當成一個新區間的開始(2) 或者是它不是新區間的開始點(1)
①(x1,y1),(x2,y2)...(xi,yi,num[j])
②(x1,y1),(x2,y2)...(xi-1,yi-1),...,(num[j]),其中yi-1是第k個數字
故:d[i][j]=max( ?d[i][j-1] ? , ?d[i-1][k] ? )+num[j],其中k=i-1,i,...,j-1
優化方法
注意到,d[i][*]只和d[i][*],d[i-1][*]有關,即當前狀態只與前一狀態有關,可以用滾動數組完成
d[t][j]=max(d[t][j-1],d[1-t][k])+num[j],其中k=i-1,i,...,j-1,t=1
其中只需要記錄兩個狀態,當前狀態t=1,上一狀態t=0
空間優化了但時間沒有優化
?
考慮我們也不需要j-1之前的最大和具體發生在k位置,只需要在j-1處記錄最大和即可,用pre[j-1]記錄即可
pre[j-1],不包括num[j-1]的j-1之前的最大和
則d[t][j]=max(d[t][j-1],pre[j-1])+num[j]
此時可以看見,t這一維也可以去掉了
即最終的狀態轉移為
d[j]=max(d[j-1],pre[j-1])+num[j]
#include <iostream> #include<cstdio> #include<memory.h> using namespace std; const int maxn=1000005; const int maxm=100; const int inf=0x7ffffff; //int d[maxm][maxn]; int num[maxn]; int d[maxn]; int pre[maxn]; /* int main() {freopen("in.txt","r",stdin);int m,n,tmp;while(cin>>m>>n){for(int i=1;i<=n;++i){cin>>num[i];}//dp[i][j],第j個人放在第i組時的最大值(1<=i<=j<=n,1<=i<=m)for(int i=0;i<=n;++i){d[0][i]=0;d[i][0]=0;}for(int i=1;i<=m;++i){for(int j=i;j<=n;++j){tmp=-inf;for(int k=i-1;k<=j-1;++k){if(tmp<d[i-1][k])tmp=d[i-1][k];}d[i][j]=max(d[i][j-1],tmp)+num[j];}}cout<<d[m][n]<<endl;}return 0; } */ int main() {//freopen("in.txt","r",stdin);int m,n,tmp;while(cin>>m>>n){int tmp;for(int i=1;i<=n;++i){cin>>num[i];}//dp[i][j],第j個人放在第i組時的最大值(1<=i<=j<=n,1<=i<=m)memset(d,0,sizeof(d));memset(pre,0,sizeof(pre));for(int i=1;i<=m;++i){tmp=-inf;for(int j=i;j<=n;++j){d[j]=max(d[j-1],pre[j-1])+num[j];pre[j-1]=tmp;tmp=max(tmp,d[j]);}}cout<<tmp<<endl;}return 0; } View Code?
hdu1025 最長上升子序列+二分優化??????
https://blog.csdn.net/u011721440/article/details/21107113
現在,我們仔細考慮計算dp[t]時的情況。假設有兩個元素a[x]和a[y],滿足?
(1)x?<?y?<?t
(2)a[x]?<?a[y]?<?a[t]
(3)dp[x]?=?dp[y]
此時,選擇dp[x]和選擇dp[y]都可以得到同樣的dp[t]值,那么,在最長上升子序列的這個位置中,應該選擇a[x]還是應該選擇a[y]呢??
很明顯,選擇a[x]比選擇a[y]要好。因為由于條件(2),在a[x+1]?...?a[t-1]這一段中,如果存在a[z],a[x]?<?a[z]?<?a[y],則與選擇a[y]相比,將會得到更長的上升子序列。?
再根據條件(3),我們會得到一個啟示:根據dp[]的值進行分類。對于dp[]的每一個取值k,我們只需要保留滿足dp[t]?=?k的所有a[t]中的最小值。設D[k]記錄這個值,即D[k]?=?min{a[t]}?(dp[t]?=?k)。?
注意到D[]的兩個特點:?
(1) D[k]的值是在整個計算過程中是單調不上升的。?
(2) D[]的值是有序的,即D[1]?<?D[2]?<?D[3]?<?...?<?D[n]。?
利用D[],我們可以得到另外一種計算最長上升子序列長度的方法。設當前已經求出的最長上升子序列長度為len。先判斷a[t]與D[len]。若a?[t]?>?D[len],則將a[t]接在D[len]后將得到一個更長的上升子序列,len?=?len?+?1,?D[len]?=?a?[t];否則,在D[1]..D[len]中,找到最大的j,滿足D[j]?<?a[t]。令k?=?j?+?1,則有a?[t]?<=?D[k],將a[t]接在D[j]后將得到一個更長的上升子序列,更新D[k]?=?a[t]。最后,len即為所要求的最長上?升子序列的長度。?
在上述算法中,若使用樸素的順序查找在D[1]..D[len]查找,由于共有O(n)個元素需要計算,每次計算時的復雜度是O(n),則整個算法的時間復雜度為O(n^2),與原來的算法相比沒有任何進步。但是由于D[]的特點(2),我們在D[]中查找時,可以使用二分查找高效地完成,則整個算法的時間復雜度下降為O(nlogn),有了非常顯著的提高。需要注意的是,D[]在算法結束后記錄的并不是一個符合題意的最長上升子序列!
#include <stdio.h> #include <iostream> #include <algorithm> using namespace std; int a[100005],dp[100005]; int main() {int n,x,y,count=1;while(~scanf("%d",&n)){for(int i=1; i<=n; i++){scanf("%d%d",&x,&y);a[x]=y;}int len=1;dp[1]=a[1];for(int i=1; i<=n; i++){int l=1;int r=len;while(l<=r){int mid=(l+r)/2;if(dp[mid]>=a[i])r=mid-1;elsel=mid+1;}dp[l]=a[i];if(l>len)len++;}printf("Case %d:\nMy king, at most %d road",count++,len);if(len!=1) printf("s");printf(" can be built.\n\n");} } View Code?
hdu1026廣搜+優先隊列+遞歸打印路徑
#define _CRT_SECURE_NO_DEPRECATE #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 #include<iostream> #include<algorithm> #include<functional> #include<vector> #include<queue>using namespace std;int n, m; int dir[4][2] = { { 0,1 },{ 0,-1 },{ 1,0 },{ -1,0 } }; struct Node {int time;int x, y;int prex, prey;char ch;bool operator>(const Node & node) const{return time > node.time;}}node[105][105];bool BFS() {int i;int mx, my;Node cur;priority_queue<Node, vector<Node>, greater<Node> > pq;node[0][0].time = 0;pq.push(node[0][0]);while (!pq.empty()){cur = pq.top();pq.pop();if (cur.x == n - 1 && cur.y == m - 1)return true;for (i = 0; i < 4; i++){mx = cur.x + dir[i][0];my = cur.y + dir[i][1];if (mx >= 0 && mx < n&&my >= 0 && my < m){if (node[mx][my].ch == '.'&&node[mx][my].time > cur.time + 1){node[mx][my].time = cur.time + 1;node[mx][my].prex = cur.x;node[mx][my].prey = cur.y;pq.push(node[mx][my]);}else if (node[mx][my].ch >= '1'&&node[mx][my].ch <= '9'&&node[mx][my].time > cur.time + node[mx][my].ch - '0'+1)//注意這里加1 {node[mx][my].time = cur.time + node[mx][my].ch - '0' + 1;//注意這里加1node[mx][my].prex = cur.x;node[mx][my].prey = cur.y;pq.push(node[mx][my]);}}}}return false; }void printPath(int x, int y) {if (x == 0 && y == 0)return;int prex = node[x][y].prex;int prey = node[x][y].prey;printPath(prex, prey);int prelength = node[prex][prey].time;int length = node[x][y].time;printf("%ds:(%d,%d)->(%d,%d)\n", prelength + 1, prex, prey, x, y);for (int i = prelength + 2; i <= length; i++){printf("%ds:FIGHT AT (%d,%d)\n", i, x, y);} }int main() {int i, j;while (~scanf("%d%d", &n, &m)){for (i = 0; i < n; i++){getchar();for (j = 0; j < m; j++){scanf("%c", &node[i][j].ch);node[i][j].time = INT_MAX;node[i][j].x = i;node[i][j].y = j;}}bool state = BFS();if (!state){printf("God please help our poor hero.\n");printf("FINISH\n");continue;}printf("It takes %d seconds to reach the target position, let me show you the way.\n", node[n - 1][m - 1].time);printPath(n - 1, m - 1);printf("FINISH\n");}return 0; } View Code?
hdu1027 n個數字典序排序的第m個排序 ? ?全排列也有函數。。。。。。。。。。。
next_permutation(后一個)和prev_permutation(前一個)函數
依照STL文檔的描寫敘述,next_permutation函數將按字母表順序生成給定序列的下一個較大的序列。直到整個序列為減序為止。prev_permutation函數與之相反。是生成給定序列的上一個較小的序列。
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; #define N 1047 int num[N]; int main() {int n , m , i ,k;while(~scanf("%d%d",&n,&m)){memset(num,0,sizeof(num));for(i = 0 ; i < n ; i++){num[i] = i+1;}for(i = 1 ; i < m ; i++){next_permutation(num,num+n);}for(i = 0 ; i < n-1 ; i++)printf("%d ",num[i]);printf("%d\n",num[n-1]);}return 0; } View Code?
?
hdu1028 ?母函數和dp ?都是大boss。。。
看了好久模板。。也看得不是太懂,xxde ?記住不得了 ?https://blog.csdn.net/xiaofei_it/article/details/17042651
/*a[0]=1; int last=0;for(int i=0;i<n;i++) {int last2=min(last+n[i]*v[i],p);memset(b,0,sizeof(int)*(last2+1));for(int j=n1[i];j<=n2[i]&&j*v[i]<=last2;j++){for(int k=0;k<=last&&k+j*v[i]<=last2;k++)b[k+j*v[i]]+=a[k];}memcpy(a,b,sizeof(int)*(last2+1));last=last2; }*/ #include<iostream> #include<string.h> #include<stdio.h> using namespace std; int v[122],num[122]; int a[122],b[122],last,last2; int main() {int n;while(scanf("%d",&n)!=EOF){for(int i=1;i<=n;i++)v[i]=i,num[i]=n/i;//for(int i=1;i<=n;i++)//cout<<v[i]<<num[i];a[0]=1;last=0;for(int i=0;i<n;i++){int last2=min(last+num[i]*v[i],n);memset(b,0,sizeof(int)*(last2+1));for(int j=0;j<=num[i]&&j*v[i]<=n;j++){for(int k=0;k<=last&&k+j*v[i]<=last2;k++)b[k+j*v[i]]+=a[k];}memcpy(a,b,sizeof(int)*(last2+1));last=last2;}cout<<a[n]+1<<endl;} } View Code又瞅了瞅dp版的
#include<stdio.h> #include<string.h> #include<iostream> using namespace std; int main() {int n;int dp[121][121];//第一個數表示要組成的數,第二個數為組合數中最大的一個 int i,l;memset(dp,0,sizeof(dp));dp[1][1]=1;for(int i=1;i<=120;i++){dp[i][1]=1;dp[1][i]=1;}for(int i=2;i<=120;i++){for(int j=2;j<=120;j++){if(i>j) d[i][j]=d[i-j][j]+d[i][j-1];else if(i==j) d[i][j]=1+d[i][j-1];else d[i][j]=d[i][i];}} while(scanf("%d",&n)!=EOF){cout<<dp[n][n]<<endl;}return 0; } View Code想了半天自己對壓縮又有點理解了,就是想辦法把j或者i通過循環的方式來降維
比如dp[10][7]=dp[3][7]+dp[10][6] ? ?注意dp[3][7]=dp[3][6];所以最終方程為
for (int i = 1; i <= 3; i++)
 {
 for (int j = 1; j <= n; j++)
 {
 dp[j] += dp[j - i];
 }
 } 
?
hdu1029水過
hdu1030 ?規律題https://www.cnblogs.com/ACMan/archive/2012/05/30/2526798.html
轉載于:https://www.cnblogs.com/wpbing/p/9357682.html
總結
                            
                        - 上一篇: LeaFlet学习之GridLayer扩
 - 下一篇: numpy-自定义ufunc函数和广播