我的漲(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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章