最近又是玩的昏天黑地的,有一段时间没有打BC了。虽然有做小题,但是快有一个礼拜没有集中敲大题了,汗!acm真是一个需要毅力与坚持的竞赛,最近我手又生了。果然,连着两次BC掉分,虽然说掉的很冤枉。
怎么说呢,还是自己比较菜把。这次第一道水题不去说它,第二道DP题目怪我做的题目比较少,但是事后想一想觉得自己也是应该想到结果会爆long long的,但是没想过会使用到高精度。汗!以前都是照着模版敲的,果然没有理解。还有就是最近作死,觉得自己可以使用VIM了,但是真到用的时候,各种错误发生。还有就是自己不会有计划的打比赛,在第二道卡死的情况下,还是一直磨,把时间全浪费了,如果转换心情去敲第三题的话,那么我就不会掉分了。汗!还是自己太年轻,经验不足。第三题还是很简单的,我这个dp外行稍微想了一下就有思路了,时=事后还是1A,觉的自己还是可以的,毕竟没怎么准备DP过。
主要是我比赛的时候太紧张了,因为不小心碰到以前的队友,虽然觉得比不过他,但是也觉得不应该比他特别菜。结果他连过两题,我这边又出现了编译器的使用错误,结果心境就崩溃了,然后就是12连WA,唉!真丢人!
对了,我发现自己还有一个问题在这次比赛中暴露了出来,就是想不到什么变量名,总是那几个,结果逻辑一塌糊涂。
hdu5567-sequence1
水题没啥好说,暴力就可以过。
#include <map> #include <set> #include <stack> #include <cmath> #include <queue> #include <bitset> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstdlib> #include <sstream> #include <cstring> #include <iostream> #include <algorithm> #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define clr(x,y) memset(x,y,sizeof(x)) #define maxn 100+5 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define IT iterator typedef long long ll; const double eps = 1e-9; const double pi = acos(-1); const ll mod = 1e9+7; ll num[maxn]; int main() { int n; ll b,c; while(~scanf("%d %I64d %I64d",&n,&b,&c)) { for(int i=0;i<n;i++) scanf("%d",num+i); int ans=0; for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) if(abs(num[i]-num[j])%b==c) ans++; printf("%d\n",ans); } return 0; }
这是一道典型的DP(别问我为什么典型,连我这个DP大外行都看出这是个DP,如果你没看出来说明你DP入门都没有),比赛的时候我还用三个变量表示状态,唉,我太菜了,正常人都用两个。这表明我做的DP题太少太少了,完全没有领会DP的精髓。这道题我用d【i】【j】表示将第i个数取作上升序列的第j个数的方案数,那么所要求的就是d【n】【0】(我是从后往前取得,第n个数其实是我自己加上去的,为了方便计算,不用以后在加一遍)。则转移方程就是d【i】【j】+=d【k】【j+1】(k从0到i-1,而且num【k】要小于num【i】),最后用一个记忆化搜索就好了。
但是这道题还有一个坑点就是结果会爆long long,那么我们怎么办呢,答案是高精度。坑就坑在这点上,其实这道题并不是特别难,状态和转移方程大多数人都会想到,但是高精度并不是人人都会想到,所以比赛的时候好多人没有做出来这道题,遗憾啊!
#include <map> #include <set> #include <stack> #include <cmath> #include <queue> #include <bitset> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstdlib> #include <sstream> #include <cstring> #include <iostream> #include <algorithm> #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define clr(x,y) memset(x,y,sizeof(x)) #define maxn 100+5 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define IT iterator typedef long long ll; const double eps = 1e-9; const double pi = acos(-1); const ll mod = 1e9+7; int n,k; ll num[maxn]; string d[maxn][maxn]; string add(string str1,string str2); string dp(int i,int j) { if(j==k)return d[i][j]="1"; if(d[i][j]!="-1")return d[i][j];; string ans="0"; for(int k=0;k<i;k++) if(num[k]<num[i]) ans=add(ans,dp(k,j+1)); return d[i][j]=ans; } string add(string str1,string str2) { string str; int len1=str1.length(); int len2=str2.length(); //前面补0,弄成长度相同 if(len1<len2) { for(int i=1;i<=len2-len1;i++) str1="0"+str1; } else { for(int i=1;i<=len1-len2;i++) str2="0"+str2; } len1=str1.length(); int cf=0; int temp; for(int i=len1-1;i>=0;i--) { temp=str1[i]-'0'+str2[i]-'0'+cf; cf=temp/10; temp%=10; str=char(temp+'0')+str; } if(cf!=0) str=char(cf+'0')+str; return str; } int main() { while(~scanf("%d %d ",&n,&k)) { for(int i=0;i<n;i++) scanf("%I64d",num+i); num[n]=0xffffffff; for(int i=0;i<maxn;i++) for(int j=0;j<maxn;j++) d[i][j]="-1"; cout<<dp(n,0)<<endl; } return 0; }
这道也是一道典型的DP,转移方程只需要稍微转换一下思路。
一开始我想这是两两配对相乘,那么要不要来个全局变量mark记录前面有没有它的搭档,但是细想了一下发现不对,这种写法太麻烦了,我估计可能写不出来。然后两两配对提醒了我,那么我为什么不能连着走两步,这样的就解决了配对的问题。我又想最后的路线数据肯定是偶数个,那么我这样写是完全可以的。
那么我就用d【i】【j】表示走到第i行第j列个格子(这个格子不算)的时候我所使用的最小贡献。那么按照要题意,转移方程为d【i】【j】=min(d【i+2】【j】+num【i】【j】*num【i+1】【j】,d【i+1】【j+1】+num【i】【j】*num【i+1】【j】,d【i+1】【j+1】+num【i】【j】*num【i】【j+1】,d【i】【j+2】+num【i】【j】*num【i】【j+1】)分别对应四种走法(连着两步下、连着两步右、先下再右、先右再下)。边界条件为走到num【n-1】【m】或者num【n】【m-1】,这个还是很好想的。记忆化搜索,然后大功告成!
#include <map> #include <set> #include <stack> #include <cmath> #include <queue> #include <bitset> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstdlib> #include <sstream> #include <cstring> #include <iostream> #include <algorithm> #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define clr(x,y) memset(x,y,sizeof(x)) #define maxn 1000+5 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define IT iterator typedef long long ll; const double eps = 1e-9; const double pi = acos(-1); const ll mod = 1e9+7; int n,m; int num[maxn][maxn]; int d[maxn][maxn]; int dp(int i,int j) { if(d[i][j]>0)return d[i][j]; if(i==n&&j==m-1||i==n-1&&j==m)return d[i][j]=num[i][j]*num[n][m]; int minn=0x3f3f3f3f; if(i+2<=n)minn=min(minn,dp(i+2,j)+num[i][j]*num[i+1][j]); if(i+1<=n&&j+1<=m) { minn=min(minn,dp(i+1,j+1)+num[i][j]*num[i+1][j]); minn=min(minn,dp(i+1,j+1)+num[i][j]*num[i][j+1]); } if(j+2<=m)minn=min(minn,dp(i,j+2)+num[i][j]*num[i][j+1]); return d[i][j]=minn; } int main() { while(~scanf("%d %d",&n,&m)) { clr(d,0); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&num[i][j]); printf("%d\n",dp(1,1)); } return 0; }