B-number HDU - 3652

原题链接
考察:数位dp
思路:
  只从看了那道CF55D题我数位dp越写越懵(.)
  这道题用容斥原理写的,有正常的循环写法: GO
  要注意求的数不同,最后判断条件也不同.

Code

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 13;
int f[N][N][N],n;
LL pows[N];
int get(LL n)
{
	return (n%13+13)%13;
}
void init()
{
	for(int i=0;i<10;i++) f[1][i][i] = 1;
	pows[0] = 1;
	for(int i=1;i<N;i++) pows[i] = pows[i-1]*10;
	for(int i=2;i<N;i++)
	 for(int j=0;j<10;j++)
	   for(int k=0;k<10;k++)
	   {
	   	if(j==1&&k==3) continue;
	   	 for(int s=0;s<13;s++)
	   	  f[i][j][s]+=f[i-1][k][get(s-j*pows[i-1])];
	   }
}
LL dp(int n,bool ok)//不包含13 
{
	if(!n) return 1;
	vector<int> v;
	while(n) v.push_back(n%10),n/=10;
	LL res = 0; int last  =0;int now = 0;
	for(int i=v.size()-1;i>=0;i--) 
	{
		int x = v[i];
		for(int j=0;j<x;j++)
		   for(int k=0;k<13;k++)
		   {
		   	  if(last==1&&j==3) break;
		   	  if(ok)
		   	  	res+=f[i+1][j][k];
		   	  else
		   	  	if((k+now%13*pows[i+1]%13)%13!=0) 
					res+=f[i+1][j][k];
		   }
		if(x==3&&last==1) break;
		last = x;
		now = x+now*10;
		if(!i)
		{
			if(ok) res++;
			else if(now%13!=0) res++;
		} 
	}
	return res;
}
int main()
{
	init();
	while(scanf("%d",&n)!=EOF)
	{
		int a = n-n/13;//不是13倍数的数
		int b = dp(n,1)-1;//不包含13的数 
		int c = dp(n,0);//不包含13且不能被13整除的数.
		LL res = (LL)a+b-c;
		printf("%lld\n",n-res); 
	}
	return 0;
}
posted @ 2021-05-29 13:58  acmloser  阅读(31)  评论(0编辑  收藏  举报