Aninteresting game
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 210 Accepted Submission(s): 83
When we add i,we must create a new set, and put iinto it.And meanwhile we have to bring [i-lowbit(i)+1,i-1] from their original sets, and put them into the new set,too.When we put one integer into a set,it costs us one unit physical strength. But bringing integer from old set does not cost any physical strength.
After we add 1,2...n,we have q queries now.There are two different kinds of query:
1 L R:query the cost of strength after we add all of [L,R](1≤L≤R≤n)
2 x:query the units of strength we cost for putting x(1≤x≤n) into some sets.
For each case,the first line contains two integers n and q.Then q lines follow.Each line contains one query.The form of query has been shown above.
n≤10^18,q≤10^5
10 2 1 8 9 2 6
9 2
最开始用了最原始的方法for循环,统计 [i-lowbit(i)+1,i-1]之间的值,代码是这样的:
int f(int x)
{
return x-(x-(x&-x));
}
int main()
{
int sum=0;
for(int i=1;i<=9;i++) //例如1~9
{
printf("%d",f(i));
sum+=f(i);
}
printf("%d\n",sum);;
return 0;
}
1 2 1 4 1 2 1 8 1
sum=21 //结果
这样很明显会超时的。。。
观察发现,根据树状数组的原理相当于每个位置放的是1;
奇数都为1,然后偶数当中根据所在树状数组中的位置,依次2,4,8增大,我们只需统计转换为二进制后第0位直到第n位1出现的个数在乘以对应的2,4,8等等2^n即可;
0 0 0 1
0 0 1 0
0 0 1 1
*
*
*
等等
long long getans(long longx)
{
long long res=0;long long t=1; long long tt;
for(int i=0;(t<<i)<=x;i++)
{
tt=x/(t<<i);
tt-=x/(t<<(i+1));
tt*=(t<<i);
res+=tt;
}
printf("res==%lld\n",res);
return res;
}
这样循环最大的情况就是二进制的位数,所以不会超时
Query2、询问一个x,查询x在1-n的插入中一共被移动了多少次。
先尝试自己写几个实例
Numi表示i的转移次数
假设N为10
Num1: 1 2 4 8 ==共4次
Num2: 2 4 8 ==共3次
Num3: 3 4 8 ==共3次
Num4: 4 8 ==共2次
Num5: 5 6 8 ==共3次
*
*
*
Num8:8== 共1次
观察规律可知这就是lowbit的走势,代码如下:
scanf("%lld",&a);
while(a<=n)
{
num++;
a+=a&-a;
}
printf("%d\n",num);
完整代码如下:
#include<bits/stdc++.h>
using namespace std;
long long n;
int q;
long long getans(long long x)
{
long long res=0;long long t=1; long long tt;
for(int i=0;(t<<i)<=x;i++)
{
tt=x/(t<<i);
tt-=x/(t<<(i+1));
tt*=(t<<i);
res+=tt;
}
return res;
}
int main()
{
while(~scanf("%lld%d",&n,&q))
{
int f;
long long a,b,ans;
while(q--)
{
scanf("%d",&f);
if(f==1)
{
scanf("%lld%lld",&a,&b);
ans=getans(b)-getans(a-1);
printf("%lld\n",ans);
}
else{
int num=0;
scanf("%lld",&a);
while(a<=n)
{
num++;
a+=a&-a;
}
printf("%d\n",num);
}
}
}
return 0;
}