方陣裡面的dp

2022-02-02 00:56:53 字數 3417 閱讀 4756

打了一場luogu的信心賽,驚訝地發現我不會t2,感覺像這樣在矩陣裡面的dp看起來很套路的樣子,但是仔細想想還是有很多需要注意的細節。

又想到之前貌似也考過一些類似的題目 然而我並沒有改 ,於是打算補補鍋。

目前大概想到幾道題,慢慢寫吧。

luogu p1006 傳紙條 && 小集訓模擬賽5 方格取數

很簡單的兩道題。注意到在「方格取數」中,因為每個方格的數字只能取一次,因此一定不會走重複路線(當然是在所有數字都大於0的情況下)。那就和「傳紙條」是同一道題了。

陣列可以開4維,3維,貌似還有二維?因為資料範圍太小就懶得寫優化了。(資料範圍大的話貌似就要用網路流了,本orzer不會)

**:

#include using namespace std;

typedef unsigned long long ll;

int a[25][25],vis[25][25],dp[25][25][25][25];

void solve()

for(int i=1;i<=n;++i)}}

}printf("%d",dp[n][n][n][n]);

}int main()

小集訓模擬賽12 t2 小象與老鼠

比上面的方格取數稍微難一點。因為每個點對答案造成的貢獻不僅僅是這個格仔的數,還有四連通的格仔。dp時候要考慮去重的問題。

具體是要記錄每乙個dp值是從它的上面或左面轉移過來。這樣分類討論就可以去重。

**:**:

#include using namespace std;

const int maxn=1000+10;

int a[maxn][maxn];

int val[maxn][maxn],dp[maxn][maxn][2];

int n,m;

void solve()

} for(int i=1;i<=n;++i)

} dp[1][1][0]=dp[1][1][1]=val[1][1]+a[1][1];

for(int i=1;i<=n;++i)

} }printf("%d",min(dp[n][m][1],dp[n][m][0]));

}int main()

luogu p6855 「ezec-4.5」走方格(2020.10.4 君のnoip のcsp信心賽 t2)

剛剛做的新題。剛開始的時候覺得很套路,幾分鐘就把**寫出來了。調了十分鐘後過不了樣例之後才發現自己錯了。

出題人的題解

看了題解才明白。。。我太菜了

首先顯然有\(o(n^4)\) 做法。列舉所有點,嘗試將其變成0即可。

然後顯然可以優化到o(n^3)因為發現如果變成0的點不再原來的最長路上,那麼對最終答案是沒有貢獻的。因此只需要列舉最長路上的點即可。

然後考慮優化。

對於最長路上的某個點,如果把它變成0。

第一種情況,如果把它變成0,它依然在最長路上。

第二種情況,其他的格仔會變成最長路上的點。

那應該怎麼計算呢?

可以發現,如果把乙個點變成0,不影響(1,1)到這個點之前的所有點的最長路。

同時還可以發現,如果反過來想,如果把乙個點變成0,也不影響這個點之後的所有點到(n,m)的最長路。

於是我們可以預處理出兩個陣列:

dp[i][j]表示(1,1)到(i,j)的最長路,f[i][j]表示(i,j)到(n,m)的最長路。

那麼把f[i][j]變成0的答案就是圖中黃色格仔向下走,紅色格仔向右走的答案取max。

最後把所有f[i][j]的答案取min即可。

**:

#include using namespace std;

typedef long long ll;

const int maxn=2000+10;

#define gc() (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? eof : *p1++) : *p1++)

#define read() ( while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = gc(); f * x; })

char buf[1 << 20], *p1, *p2;

int a[maxn][maxn];

ll f[maxn][maxn],dp[maxn][maxn];

bool vis[maxn][maxn];

int n,m;

ll ans=0x3f3f3f3f3f3f3f3f;

struct node

node(int aa,int bb)

};queue q;

void solve()

} for(int i=1;i<=n;++i)

} for(int i=n;i;--i)

} q.push(node(n,m));

while(!q.empty())

for(int i=1;i<=n;++i)^a_i^2-(\sum_^a_i^2)^2\)

然後會發現,這個柿子的值只和每一項的值和每一項的平方有關。

於是可以定義轉移方程:

dp[i][j][k]表示當前走到(i,j),\(\sum_^a_s\) 的值為k,的最小的\(\sum_^a_s^2\)

然後轉移就很簡單啦!

**:#include using namespace std;

typedef long long ll;

const int maxn=100000+10;

#define gc() (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? eof : *p1++) : *p1++)

#define read() ( while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = gc(); f * x; })

char buf[1 << 20], *p1, *p2;

ll dp[40][40][2000];

int a[40][40];

int n,m;

ll ans;

void solve()

} memset(dp,0x3f,sizeof(dp));

dp[1][1][a[1][1]]=a[1][1]*a[1][1];

for(int i=1;i<=n;++i)

}} for(int i=0;i<=1800;++i) if(dp[n][m][i]<=1e9) ans=min(ans,1ll*(n+m-1)*dp[n][m][i]-1ll*i*i);

printf("%lld\n",ans); }}

int main()

列舉裡面的介面的實現

列舉式乙個類,這個類,同樣也有類改由的功能,今天來說說列舉來實現介面。下面還是來看看 吧.首先我們定義乙個介面 介面裡面由兩個抽象方法.如下.public inte ce enuminte ce下滿我們來定義我們的列舉型別的類,分別由三個物件,分別有自己的構造方法.如下.public enum de...

Python裡面的字典

python 將這種資料型別叫做 dict 有的語言裡它的名稱是 hash 這兩種名字都會用到,不過這並不重要,重要的是它們和列表的區別。你看,針對列表你可以做這樣的事情 things a b c d print things 1 b things 1 z print things 1 z prin...

jquery裡面的 this 和this

當你用的是jquery時,就用 this 如果是js,就用this this html this html bam 這個裡的html 是jquery方法,用 this html 當然,js裡也有相似方法innerhtml,如果用innerhtml,就要這樣寫了,這裡的reset是js方法,所以同上得...