2021.5.21讲题日

Program in C++14

据说某位神犇说过:数位DP就是抄板子的日常

对不对先不说但是要是谁有板子给我一个,数位DP确实有套路

T1:\(P2606\)

模板题不讲

如果需要,这里有神犇 \(\mathtt{zrt}\) 的视频。私信我领取,从 \(\mathtt{1:01:30}\) 开看

#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
#include<chrono>
#include<random>
#include<unordered_map>
#define ll long long
#define ull unsigned long long
#define rll register long long
#define ri register int
using namespace std;

const int N=100;
ll a,b;
ll ten[N],f[N];
ll ca[N],cb[N];

inline ll read(){
    ll x=0,y=1;
    char c=getchar();
    while (c<'0'||c>'9'){
        if(c=='-')
            y=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=x*10+c-'0';
        c=getchar();
    }
    return x*y;
}

void work(ll x,ll *c){
    ll num[20];
    memset(num,0,sizeof(0));
    int len=0;
    while(x){
        num[++len]=x%10;
        x=x/10;
    } 
    for(int i=len;i>=1;i--){
        for(int j=0;j<=9;j++)
        	c[j]+=f[i-1]*num[i];
        for(int j=0;j<num[i];j++)
        	c[j]+=ten[i-1];
        ll num2=0;
        for(int j=i-1;j>=1;j--){
            num2=num2*10+num[j];
        }
        c[num[i]]+=num2+1;
        c[0]-=ten[i-1];
    } 
}

signed main(){
    a=read();
    b=read();
    ten[0]=1;
    for(int i=1;i<=15;i++){
        f[i]=f[i-1]*10+ten[i-1];
        ten[i]=10*ten[i-1];
    }
    work(a-1,ca);
    work(b,cb);
    for(int i=0;i<=9;i++)
    	printf("%lld ",cb[i]-ca[i]);
    return 0;
}

T2:\(P2657\)

找符合规定的数,显然是数位\(DP\)

\(0\sim9\)都是\(windy\)数,所以先预处理一下

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

既然要做到每一位的递推,自然要把 \(a\)\(b\) 拆开

while(x){
		cf[++len]=x%10;
		x/=10;
	}

多举例子多算,易得状态转移方程。

对于以 \(i\) 为开头,长度为 \(j\) 的数,有

\[f[i][j]+=f[i-1][k]; \]

边界

数位\(DP\) 难就难在它的边界处理

我们不妨分情况讨论

1.数位小于 \(b\)

一加就好 \(:)\)

for(int i=1;i<=len-1;i++)
	for(int j=1;j<=9;j++)
		ans+=f[i][j];

2.数位等于 \(b\) 但最高位小于 \(b\) 的最高位

一加就好 \(:)\)

for(int i=1;i<cf[len];i++)
	ans+=f[len][i];

3.数位等于 \(b\) 且最高位等于 \(b\) 的最高位

不太好搞 \(:(\)

需要从最高位后面开始枚举

for(int i=len-1;i>=1;i--)
	for(int j=0;j<=cf[i]-1;j++)
		if(abs(j-cf[i+1])>=2)
			ans+=f[i][j];

于是乎,基本上做完了 \(qwq\)

代码

#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
#include<chrono>
#include<random>
#include<unordered_map>
using namespace std;

#define ll long long
#define ull unsigned long long
#define rll register long long
#define ri register int

const int N=21000;
int a,b;
int f[N][N];

int work(int x){
	int cf[N];
	int len=0,ans=0;
	while(x){
		cf[++len]=x%10;
		x/=10;
	}
	for(int i=1;i<=len-1;i++){
		for(int j=1;j<=9;j++)
			ans+=f[i][j];
	}
	for(int i=1;i<cf[len];i++)
		ans+=f[len][i];
	for(int i=len-1;i>=1;i--){
        for(int j=0;j<=cf[i]-1;j++){
		   	if(abs(j-cf[i+1])>=2)
				ans+=f[i][j];
		   } 
		if(abs(cf[i+1]-cf[i])<2)
			break;
    }
	return ans;
}

int main(){
	scanf("%d%d",&a,&b);	
	for(int i=0;i<=9;i++)
		f[1][i]=1;
	for(int i=2;i<=10;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];
	cout<<work(b+1)-work(a);
	return 0;
}
posted @ 2021-07-14 20:04  BFNewdawn  阅读(25)  评论(0编辑  收藏  举报