Location>code7788 >text

DP Advanced Collection

Popularity:991 ℃/2024-07-28 17:29:51

(ps: This collection of dp advanced knowledge summarized by Star_F is continuously updated~. Republishing this article need to contact me, otherwise it is considered as copyright infringement!!!)

Pre-knowledge: linear dp, backpack, tree dp, interval dp

Content Preview:

  • Shaped pressure dp
  • digital dp
  • dp optimization (prefix sums, monotonic queues, slope optimization)

1. Stress dp.

Idea: If the title of the\(n\) The range is particularly small (\(<=20\)) can probably press the dp.
State: f[i][j]: considering the former\(i\) number of them, and the set that has been considered is\(j\) (j is a binary number, 1 means considered, 0 means not considered)
set of
(Supporting knowledge: bitwise operations)

Example question:

  • P1171 Salesman's Dilemma
    dp[i][j] denotes the shortest path from the starting point to point j with state i at the arrival point.
    Compare the simple shape of the pressure dp, look at the code between it:
Click to view code
#include<bits/stdc++.h>
using namespace std;
int f[1<<20][20],w[20][20],n;
int main(){
	cin>>n;
	memset(f,0x3f,sizeof f);
	f[1][0]=0;
	for(int i=0;i<n;++i)
		for(int j=0;j<n;++j)
			cin>>w[i][j];
	for(int i=1;i<(1<<n);i+=2) //Enumeration state
		for(int j=0;j<n;j++){ //Enumerate the points reached in the next step
			if(!((i >> j) & 1)) continue;
			for(int k=0;k<n;k++){ Enumeration of intermediary points
				if(j==k) continue;
				if(!(i>>k &1)) continue;
				f[i][j]=min(f[i][j],f[i^(1<<j)][k]+w[k][j]);
			}
		}
	int minn=2e9;
	for(int i=0;i<=n-1;++i) minn=min(minn,f[(1<<n)-1][i]+w[i][0]);
	cout<<minn<<endl;
	return 0;
}
  • P1896 [SCOI2005] Non-aggression
    Idea: f[i][j][s] then represents the total number of situations when only the first i rows are considered, when there are and only s kings in the first i rows (including row i), and when the situation of the king in row i is the state numbered j. And k then represents the state number of the king's situation in row i-1.
Click to view code
#include<cstdio>
#include<cstdio> #include<iostream>
#include<cstring> #include<cmath>
#include<cmath>.
#include<string>.
#include<algorithm> #include<algorithm>
using namespace std.
int sit[2000],gs[2000].
int cnt=0;
int n,yong;
long long f[10][2000][100]={0};
void dfs(int he,int sum,int node)//preprocess out each state
{
if(node>=n)//if it has been processed (note it is greater than or equal to)
{
sit[++cnt]=he;
gs[cnt]=sum.
return; // create a new state
}
dfs(he,sum,node+1);// don't use the node one
dfs(he+(1<<node),sum+1,node+2);//use the first node, add 2 to the node, and skip the next grid.
}
int main()
{
scanf("%d%d",&n,&yong);
dfs(0,0,0);
for(int i=1;i<=cnt;i++)f[1][i][gs[i]]=1;//all states in the first level are with 1 case
for(int i=2;i<=n;i++)
for(int j=1;j<=cnt;j++)
for(int k=1;k<=cnt;k++)//enumerate i, j, k
{
if(sit[j]&sit[k])continue;
if((sit[j]<<1)&sit[k])continue;
if(sit[j]&(sit[k]<<1))continue;//exclude unlawful king cases
for(int s=yong;s>=gs[j];s--)f[i][j][s]+=f[i-1][k][s-gs[j]];//enumerate s, calculate f[i][j][s]
}
long long ans=0;
for(int i=1;i<=cnt;i++)ans+=f[n][i][yong];//count final answer, remember to use long long
printf("%lld",ans);
return 0.
}

2. Digital dp.

dp with the number of digits of a number, generally for finding the number of digits in an interval that satisfies certain conditions
The interval is usually changed to\((1...r) - (1...l-1)\)

Example question:

  • P2657windy count
    Recursive practices:
Click to view code
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 11;

int f[N][10];

void init()
{
    for (int i = 0; i <= 9; i ++ ) f[1][i] = 1;

    for (int i = 2; i < N; i ++ )
        for (int j = 0; j <= 9; j ++ )
            for (int k = 0; k <= 9; k ++ )
                if (abs(j - k) >= 2)
                    f[i][j] += f[i - 1][k];
}

int dp(int n)
{
    if (!n) return 0;

    vector<int> nums;
    while (n) nums.push_back(n % 10), n /= 10;

    int res = 0;
    int last = -2;
    for (int i = () - 1; i >= 0; i -- )
    {
        int x = nums[i];
        for (int j = i == () - 1; j < x; j ++ )
            if (abs(j - last) >= 2)
                res += f[i + 1][j];

        if (abs(x - last) >= 2) last = x;
        else break;

        if (!i) res ++ ;
    }


    for (int i = 1; i < (); i ++ )
        for (int j = 1; j <= 9; j ++ )
            res += f[i][j];

    return res;
}

int main()
{
    init();

    int l, r;
    cin >> l >> r;
    cout << dp(r) - dp(l - 1) << endl;

    return 0;
}

  • CF628D
    Recursive approach, enumerate to that bit, now the attributes, are there any restrictions
Click to view code
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int mod = 1e9+7;
ll m,d,a[2005],len,f[2005][2005];
char l[2005],r[2005];
ll dfs(int u,int sum,int yaoqiu){
	if(u>len) return sum==0?1:0;
	if(!yaoqiu&&f[u][sum]!=-1) return f[u][sum];
	ll tmp=0,maxx=yaoqiu==1?a[u]:9;
	if(u%2==1){
		for(int i=0;i<=maxx;i++)
			if(i!=d) tmp=(tmp+dfs(u+1,(sum*10+i)%m,yaoqiu&&(i==maxx)))%mod;
	}
	else{
		for(int i=0;i<=maxx;i++)
			if(i==d) tmp=(tmp+dfs(u+1,(sum*10+i)%m,yaoqiu&&(i==maxx)))%mod;
	}
	if(!yaoqiu) f[u][sum]=tmp;
	return tmp;
}
ll dp(char *s){
	memset(f,-1,sizeof(f)); 
	len=strlen(s+1);
	for(int i=1;i<=strlen(s+1);i++) a[i]=s[i]-'0';
	return dfs(1,0,1);
}
bool check(char *s){
    len=strlen(s+1);
    int x=0;
    for(int i=1;i<=len;i++){
        int y=s[i]-'0';
        x=(x*10+y)%m;
        if(i&1){
            if(y==d)
                return false;
        }
        else{
            if(y!=d)
                return false;
        }
    }
    return !x;
}
int main(){
	cin>>m>>d>>l+1>>r+1;
	cout<<(dp(r)-dp(l)+check(l)+mod)%mod;
    return 0;
}

Optimization: