专栏文章

题解:CF2086E Zebra-like Numbers

CF2086E题解参与者 3已保存评论 7

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
7 条
当前快照
1 份
快照标识符
@mipn8snb
此快照首次捕获于
2025/12/03 14:46
3 个月前
此快照最后确认于
2025/12/03 14:46
3 个月前
查看原文
一道不那么板的数位 DP,感觉思路很清奇。
显然斑马数不超过 3030 个,记斑马数为 numinum_i,那么答案是一个多项式的形式,考虑将其转化为进制的形式。
考虑这个进制,由于斑马值是最小的系数和,从高位到低位贪心一定是最优的。并且由于有 numi=numi1×4+1num_i=num_{i-1}\times 4+1,所以每一位上的数值都不大于 44,并且如果有一位为 44,则它的更低位一定是 00
那么 DP 状态为 dpi,j,lim1,lim2dp_{i,j,lim1,lim2},表示当前 pospos 位,数位和为 jj,是否达到数值限制,是否出现了 44,转移即可。
代码:
CPP
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline ll read(){
	ll x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*f;
}
bool mbs;
ll t,l,r,k,num[32],val[32],dp[32][100][2][2];
ll dfs(int pos,int sum,int lim1,int lim2){
	if(!pos) return sum==k;
	if(dp[pos][sum][lim1][lim2]!=-1) return dp[pos][sum][lim1][lim2];
	int up=4;ll res=0;
	if(lim2) up=0;
	else if(lim1) up=val[pos];
	for(int i=0;i<=up;i++) res+=dfs(pos-1,sum+i,lim1&&i==val[pos],lim2||i==4);
	return dp[pos][sum][lim1][lim2]=res;
}
inline ll get_val(ll x){
	for(int i=30;i>=1;i--) val[i]=(x/num[i]),x-=(x/num[i])*num[i];
	memset(dp,-1,sizeof(dp));
	return dfs(30,0,1,0);
}
inline void solve(){
	l=read(),r=read(),k=read();
	printf("%lld\n",get_val(r)-get_val(l-1));
}
bool mbt;
int main(){
//	cout<<(&mbs-&mbt)/1024.0/1024.0<<endl;
	num[1]=1;
	for(int i=2;i<=30;i++) num[i]=num[i-1]*4+1;
	t=read();
	while(t--) solve();
	return 0;
}

评论

7 条评论,欢迎与作者交流。

正在加载评论...