Aninteresting game HDU - 5975 (数学+lowbit)
Let’s play a game.We add numbers 1,2...n in increasing order from 1 and put them into some sets.
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.
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.
InputThere are several cases,process till end of the input.
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
OutputFor each query, please output one line containing your answer for this querySample Input
10 2 1 8 9 2 6
Sample Output
9 2
Hint
lowbit(i) =i&(-i).It means the size of the lowest nonzero bits in binary of i. For example, 610=1102, lowbit(6) =102= 210 When we add 8,we should bring [1,7] and 8 into new set. When we add 9,we should bring [9,8] (empty) and 9 into new set. So the first answer is 8+1=9. When we add 6 and 8,we should put 6 into new sets. So the second answer is 2.
题意:
多组输入,。每一组数据,有一个数字n,和一个数q,
有1~n个数,将i放入集合中同时放入i-lowbit(i)+1~ i 的所有数。
每向集合中放入一个数,就会消耗一点体力值。
然后有q个询问,询问1是,给你一个l和r,问l~r每一个数都加入到集合中,会消耗多少体力值。
2.
1~n中,对每一个数进行加入到集合中的话,数x会被加入多少次。
思路:
把i放入集合就会放入i-lowbit(i)+1~i的所有数
那么一共就是加入i - (i-lowbit(i)+1) +1 个数,即lowbit(i)个数,
那么一个数i消耗的体力值就是lowbit(i)
那么第一问就是让求l~r的lowbit的sum和。
由于数据量很大,我们不能扫一遍算出,
那么我们来分析一下是否可以优化。,
我们知道,lowbit(i)表示的是数字i的二进制最低位代表的十进制数。
例如6的二进制是110,最低位时第2个1,从右向左第2位,代表的十进制时2,(二进制10是十进制的2),那么lowbit(6)就是2。
那么l~r的lowbit的sum和就是,最低位的1在0位置上的数的数量*1(代表的十进制)+ 最低位的1在1位置上的数的数量*2 +.....
那么问题转化为如何快速的求出l~r中最低位的1在第i位的数的数量,
我们知道这样的一个求解方法(容斥的思想)n/(1<<P)-n/(1<<(p+1))就是·1~n中最低位的1在第p位(从右向左数,0开始计位)的数的数量。
那么我们只需要logn来枚举每一位,然后上面的公式即可计算出每一位的数量。
然后我们来看第二个问题,
要找到x在几个集合中,可用x=x+lowbit(x)找出有多少满足条件的x,就能得到集合的个数
细节见代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #include <iomanip> #define ALL(x) (x).begin(), (x).end() #define rt return #define dll(x) scanf("%I64d",&x) #define xll(x) printf("%I64d\n",x) #define sz(a) int(a.size()) #define all(a) a.begin(), a.end() #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define pii pair<int,int> #define pll pair<long long ,long long> #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define MS0(X) memset((X), 0, sizeof((X))) #define MSC0(X) memset((X), '\0', sizeof((X))) #define pb push_back #define mp make_pair #define fi first #define se second #define eps 1e-6 #define gg(x) getInt(&x) #define db(x) cout<<"== [ "<<x<<" ] =="<<endl; using namespace std; typedef long long ll; ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} ll lcm(ll a,ll b){return a/gcd(a,b)*b;} ll powmod(ll a,ll b,ll MOD){ll ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;} inline void getInt(int* p); const int maxn=1000010; const int inf=0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ ll solve(ll x) { ll res=0ll; for(ll p=1ll;p<=x;p<<=1) { res+=(x/p-x/(p<<1))*p; } return res; } ll lowbit(ll x) { return x&(-x); } ll solve2(ll x,ll n) { ll res=0ll; while(x<=n) { res++; x+=lowbit(x); } return res; } int main() { //freopen("D:\\common_text\\code_stream\\in.txt","r",stdin); //freopen("D:\\common_text\\code_stream\\out.txt","w",stdout); ll n,q; while(~scanf("%lld %lld",&n,&q)) { int op; while(q--) { scanf("%d",&op); if(op==1) { ll l,r; scanf("%lld %lld",&l,&r); ll res=solve(r)-solve(l-1ll); printf("%lld\n",res ); }else { ll x; scanf("%lld",&x); printf("%lld\n",solve2(x,n) ); } } } return 0; } inline void getInt(int* p) { char ch; do { ch = getchar(); } while (ch == ' ' || ch == '\n'); if (ch == '-') { *p = -(getchar() - '0'); while ((ch = getchar()) >= '0' && ch <= '9') { *p = *p * 10 - ch + '0'; } } else { *p = ch - '0'; while ((ch = getchar()) >= '0' && ch <= '9') { *p = *p * 10 + ch - '0'; } } }
本博客为本人原创,如需转载,请必须声明博客的源地址。
本人博客地址为:www.cnblogs.com/qieqiemin/
希望所写的文章对您有帮助。