我的涨(diao)分日记(三)——BestCoder Round #63

最近又是玩的昏天黑地的,有一段时间没有打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;
}

hdu5568- sequence2

这是一道典型的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;
}

hdu5569-matrix

这道也是一道典型的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;
}


你可能感兴趣的:(BestCoder)