题意:
把1到n(1<=n<=1e15)写在一行,给每个数位间隔地加加减号,像这样:
n=12: +1 -2 +3 -4 +5 -6 +7 -8 +9 -1+0 -1+1 -1+2=5
给你n问上面这个式子的结果是多少
大致思路:
数位DP,找下规律发现数位长度为偶数的数都是以-开头,数位长度为奇数再分两种情况:这个数是偶数则以-开头,这个数是奇数则以+开头
那么开个记忆化搜索:
dfs(长度,当前符号,所求数位长度奇偶性,所求数奇偶性,前缀0标记,上限标记)
由于要计算权值所以还要再开一个记忆化搜索计算合法数的个数:
dfs2(长度,所求数奇偶性,上限标记)由于实现细节的关系这里省了数位长度奇偶性和前缀0标记
详细转移看代码,有比较多细节要注意
想了一晚上,不容易啊
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<iomanip>
#include<vector>
#include<set>
#include<map>
#include<queue>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define rep(i,k,n) for(int i=(k);i<=(n);i++)
#define rep0(i,n) for(int i=0;i<(n);i++)
#define red(i,k,n) for(int i=(k);i>=(n);i--)
#define sqr(x) ((x)*(x))
#define clr(x,y) memset((x),(y),sizeof(x))
#define pb push_back
#define mod 1000000007
int a[20];
LL dp[20][3][2],dp2[20][2];
LL dfs2(int pos,int valp,bool up)
{
if(!up && dp2[pos][valp]!=-1)return dp2[pos][valp];
int upp=up?a[pos]:9;
LL ret=0;
if(pos==1)
{
rep(i,0,upp)if(i%2==valp)ret++;
}
else
{
rep(i,0,upp)ret+=dfs2(pos-1,valp,up&&i==a[pos]);
}
if(!up)dp2[pos][valp]=ret;
return ret;
}
LL dfs(int pos,int sign,int lenp,int valp,bool z,bool up)
{
if(!z && !up && pos%2==lenp && dp[pos][sign+1][valp]!=-1)return dp[pos][sign+1][valp];
int upp=up?a[pos]:9;
LL ret=0;
if(pos==1)
{
if(z && pos%2!=lenp)return 0;
rep(i,0,upp)if(i%2==valp)
{
ret+=sign*i;
}
}
else
{
if(z)
{
ret+=dfs(pos-1,sign,lenp,valp,1,up && a[pos]==0);
if(pos%2==lenp)
{
rep(i,1,upp)
ret+=dfs(pos-1,-sign,lenp,valp,0,up && i==a[pos])+i*sign*dfs2(pos-1,valp,up && i==a[pos]);
}
}
else
{
rep(i,0,upp)
ret+=dfs(pos-1,-sign,lenp,valp,0,up && i==a[pos])+i*sign*dfs2(pos-1,valp,up && i==a[pos]);
}
}
if(!z && !up && pos%2==lenp)dp[pos][sign+1][valp]=ret;
return ret;
}
LL calc(LL x)
{
int len=0;
while(x)a[++len]=x%10,x/=10;
LL d1=dfs(len,-1,0,0,1,1),d2=dfs(len,-1,0,1,1,1),d3=dfs(len,-1,1,0,1,1),d4=dfs(len,+1,1,1,1,1);
// cout<<d1<<' '<<d2<<' '<<d3<<' '<<d4<<endl;
return d1+d2+d3+d4;
}
void init()
{
clr(dp,-1);
clr(dp2,-1);
}
int main()
{
init();
LL n;
while(~scanf("%lld",&n))
{
if(n==0)break;
printf("%lld\n",calc(n));
}
return 0;
}