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 "); else printf("no "); } return 0; }
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 "); } return 0; }
hdu1023 什么什么卡特兰数。。。
这个还是卡特兰数+大数
https://blog.csdn.net/wu_tongtong/article/details/78161211
卡特兰数规律

#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(" "); } return 0; }
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; }
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; else l=mid+1; } dp[l]=a[i]; if(l>len) len++; } printf("Case %d: My king, at most %d road",count++,len); if(len!=1) printf("s"); printf(" can be built. "); } }
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;//注意这里加1 node[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) ", prelength + 1, prex, prey, x, y); for (int i = prelength + 2; i <= length; i++) { printf("%ds:FIGHT AT (%d,%d) ", 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. "); printf("FINISH "); continue; } printf("It takes %d seconds to reach the target position, let me show you the way. ", node[n - 1][m - 1].time); printPath(n - 1, m - 1); printf("FINISH "); } return 0; }
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 ",num[n-1]); } return 0; }
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; } }
又瞅了瞅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; }
想了半天自己对压缩又有点理解了,就是想办法把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];
}
}

#include <iostream> using namespace std; const int M = 32768 + 10; int dp[M]; int main() { int n; while (~scanf("%d", &n)) { memset(dp, 0, sizeof(dp)); dp[0] = 1; for (int i = 1; i <= 3; i++) { for (int j = 1; j <= n; j++) { dp[j] += dp[j - i]; } } printf("%d ", dp[n]); } return 0; }
hdu1029水过
hdu1030 规律题https://www.cnblogs.com/ACMan/archive/2012/05/30/2526798.html