原题:Code for 1
题意:给定一个数N,对大于1的数在原来的位置拆分为N/2,N%2,N/2三个数。对拆分出的大于1的数同样进行拆分,直至所有的数均为0或1。对拆分后的0/1序列,询问L到R区间中1的数量。
看到这题,我直接想都没想就直接模拟了,(可能比赛的时候脑子属于装饰品)结果理所当然ML了。
后来才知道其实不需要还原最后的串就可以解答,直接用dfs做就可以了,先到了这题真的很水,代码很短。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<list>
#include<vector>
#include<stack>
#include<queue>
#include<functional>
#define D long long
#define F double
#define MAX 0x7fffffff
#define MIN -0x7fffffff
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define pill pair<int, int>
using namespace std;
#define N 100100
#define MOD ((int)1e9+7)
D dfs(D n,D L,D R,D l,D r){
if(L>r||R<l)return 0;
if(n==0)return 0;
if(n==1)return 1;
return dfs(n/2,L,R,l,(l+r>>1)-1)+dfs(n%2,L,R,(l+r>>1),(l+r>>1))+dfs(n/2,L,R,(l+r>>1)+1,r);
}
int main()
{
D num,L,R;
cin>>num>>L>>R;
D len=1;D num_=num;
while(num>1){
len*=2;len++;num/=2;
}
cout<<dfs(num_,L,R,1,len)<<endl;
return 0;
}
首先求出最终串的长度,用长度来代替串。
然后二分区间,如果是无用(在要求的区间外),则return 0,如果是有用的,分为两种,一种是单点,可以直接得到值,一种是区域,就继续往下dfs。
可以意会一下下面的模拟过程图
这里模拟的是L到(1+len)/2 段。