SP10606 BALNUM - Balanced Numbers 题解
很久以前积的题解,因为比目前的题解更优,就从博客园搬过来了。
更好的阅读体验
本题解提供
使用
所以用
注意到数据范围,可能需要开unsigned long long,注意这样bool类型的
#include<bits/stdc++.h>
#define int unsigned long long
using namespace std;
int t,l,r,a[30];
bitset<10> vis,sta;
bool fv[30][1024][1024];
int f[30][1024][1024];
int dfs(int pos,bool limit,bool zero){
if(pos==0){
for(int i=0;i<=9;i++) if(vis[i]&&sta[i]==i%2) return 0;
return 1;
}
int numvis=vis.to_ullong(),numsta=sta.to_ullong();
if(!limit&&!zero&&fv[pos][numvis][numsta])
return f[pos][numvis][numsta];
int rig=limit?a[pos]:9,ans=0;
for(int i=0;i<=rig;i++){
bool is=(zero&&i==0);
bool tvis=vis[i],tsta=sta[i];
if(!is) vis[i]=1,sta[i]=!sta[i];
ans+=dfs(pos-1,limit&&i==rig,is);
vis[i]=tvis,sta[i]=tsta;
}
if(!limit&&!zero) f[pos][numvis][numsta]=ans,fv[pos][numvis][numsta]=1;
return ans;
}
int solve(int x){
int len=0;
while(x){
a[++len]=x%10;
x/=10;
}
return dfs(len,1,1);
}
signed main(){
memset(fv,0,sizeof fv);
cin>>t;
while(t--){
cin>>l>>r;
cout<<solve(r)-solve(l-1)<<endl;
}
return 0;
}
空间优化
其实上面的就能过了,但是我们注意到还有优化空间。
上面的表示其实就是四进制,但是我们发现
按道理说应该只是优化了空间而没有优化时间,因为上面所说的情况根本不会搜索到。
(但很奇怪的是这份代码跑得奇快,具体见下面的时间对比,如果大家有解答请在评论区告诉我,谢谢!)
#include<bits/stdc++.h>
#define int unsigned long long
using namespace std;
int t,l,r,a[30];
int sta[10];
bool fv[30][59049];
int f[30][59049];
//0没访问,1访问奇数次,2访问偶数次,10位三进制
//优化掉了“没访问过,奇数次”的状态
int to_num(){
int ans=0;
for(int i=0;i<=9;i++) ans=ans*3+sta[i];
return ans;
}
int dfs(int pos,bool limit,bool zero){
if(pos==0){
for(int i=0;i<=9;i++){
if(sta[i]==0) continue;
if(sta[i]-1!=i%2) return 0;
}
return 1;
}
int numsta=to_num();
if(!limit&&!zero&&fv[pos][numsta])
return f[pos][numsta];
int rig=limit?a[pos]:9,ans=0;
for(int i=0;i<=rig;i++){
bool is=(zero&&i==0);
int tsta=sta[i];
if(!is) sta[i]=(sta[i]==0||sta[i]==2)?1:2;
ans+=dfs(pos-1,limit&&i==rig,is);
sta[i]=tsta;
}
if(!limit&&!zero) f[pos][numsta]=ans,fv[pos][numsta]=1;
return ans;
}
int solve(int x){
int len=0;
while(x){
a[++len]=x%10;
x/=10;
}
return dfs(len,1,1);
}
signed main(){
memset(fv,0,sizeof fv);
cin>>t;
while(t--){
cin>>l>>r;
cout<<solve(r)-solve(l-1)<<endl;
}
return 0;
}
进一步时空优化
结论:只要vis奇数位上1的个数、vis偶数位上1的个数、sta奇数位上1的个数、sta偶数位上1的个数都分别相等,两种状态答案就一样。所以可以直接使用
为什么呢?如果你一共访问了
#include<bits/stdc++.h>
#define int unsigned long long
using namespace std;
int t,l,r,a[30];
bitset<10> vis,sta;
bool fv[30][1296];
int f[30][1296];
int dfs(int pos,bool limit,bool zero){
if(pos==0){
for(int i=0;i<=9;i++) if(vis[i]&&sta[i]==i%2) return 0;
return 1;
}
int num=(vis[0]+vis[2]+vis[4]+vis[6]+vis[8]);
num=num*6+(vis[1]+vis[3]+vis[5]+vis[7]+vis[9]);
num=num*6+(sta[0]+sta[2]+sta[4]+sta[6]+sta[8]);
num=num*6+(sta[1]+sta[3]+sta[5]+sta[7]+sta[9]);
if(!limit&&!zero&&fv[pos][num])
return f[pos][num];
int rig=limit?a[pos]:9,ans=0;
for(int i=0;i<=rig;i++){
bool is=(zero&&i==0);
bool tvis=vis[i],tsta=sta[i];
if(!is) vis[i]=1,sta[i]=!sta[i];
ans+=dfs(pos-1,limit&&i==rig,is);
vis[i]=tvis,sta[i]=tsta;
}
if(!limit&&!zero){
f[pos][num]=ans,fv[pos][num]=1;
}
return ans;
}
int solve(int x){
int len=0;
while(x){
a[++len]=x%10;
x/=10;
}
return dfs(len,1,1);
}
signed main(){
memset(fv,0,sizeof fv);
cin>>t;
while(t--){
cin>>l>>r;
cout<<solve(r)-solve(l-1)<<endl;
}
return 0;
}
运行消耗对比
从上到下分别是洛谷题解(by Fuko_Ibuki)、朴素算法、空间优化、究极时空优化的代码的运行消耗,每个样例测试点均在