Codeforces Round #553 (Div. 2) C. Problem for Nazar

题目链接:https://codeforc.es/contest/1151/problem/C

题意:有两个无限的奇数集合和偶数集合 构造一个新的数组,先是放前2^0  个奇数, 然后集合中移除这些数,在放2^1 个偶数 进去新的数组,重复操作

思路:看见2的幂 就知道可以直接来logn模拟了, 自己做的时候考虑的时候是用前缀和记录每一份奇数和偶数有多少个,并且记录下每一份的长度和首项,后面用等差数列来求和即可

中间的直接相加,唯有前面多出来的一点和后面多出来的一点要处理一下, 不过要注意可能没有中间部分,即只有一段要单独处理一下

 1 #include
 2 using namespace std;
 3 #define ll long long
 4 #define pb push_back
 5 const int maxn =2e5+10;
 6 const int mod=1e9+7;
 7 ll a[100];
 8 ll len[100];
 9 ll pre[maxn];
10 
11 
12 
13 int main()
14 {
15     ios::sync_with_stdio(false);
16     cin.tie(0);
17     ll l,r;
18     cin>>l>>r;
19     ll g=1;
20     ll cnt1=1;
21     ll cnt2=2;
22     for(int i=1;i<=60;i++)
23     {
24         len[i]=g;
25         g*=2;
26         if(i%2)
27         {
28             a[i]=cnt1;
29             cnt1+=1ll*len[i]*2;
30         }
31         else
32         {
33             a[i]=cnt2;
34             cnt2+=1ll*len[i]*2;
35         }
36     }
37 
38     ll ans=0;
39     for(int i=1;i<=60;i++)
40     {
41         pre[i]=pre[i-1]+len[i];
42     }
43     int p=lower_bound(pre+1,pre+1+60,l)-pre;
44     int pos=lower_bound(pre+1,pre+1+60,r)-pre;
45     if(p==pos)
46     {
47         ll len2=r-pre[p-1];
48         ll temp=a[p]%mod*(len2%mod)+len2%mod*((len2%mod-1+mod)%mod);
49         temp%=mod;
50         ans+=temp;
51         ans%=mod;
52         ll len3=l%mod-pre[p-1]%mod-1;
53         len3=(len3+mod)%mod;
54         ll temp2=a[p]%mod*(len3%mod)+len3%mod*((len3%mod-1+mod)%mod);
55         temp2%=mod;
56         ans-=temp2;
57         ans=(ans+mod)%mod;
58         cout<'\n';
59         return 0;
60     }
61 
62     for(int i=p+1;i<=pos-1;i++)
63     {
64         ll temp=a[i]%mod*(len[i]%mod)+len[i]%mod*((len[i]%mod-1+mod)%mod);
65         temp%=mod;
66         ans+=temp;
67         ans%=mod;
68     }
69 
70     ll len2=r-pre[pos-1];
71     ll temp2=(len2%mod*(a[pos]%mod));
72     temp2%=mod;
73     ll temp3=((len2%mod-1+mod)%mod)*(len2%mod);
74     temp3%=mod;
75     ans+=temp2+temp3;
76     ans%=mod;
77 
78 
79     ll len1=pre[p]%mod-l%mod+1;
80     len1=(len1+mod)%mod;
81     ll a1=a[p]%mod+(len[p]%mod-len1%mod+mod)%mod*2;
82     ll temp1=(len1%mod*(a1%mod))%mod;
83     ll temp4=((len1%mod-1+mod)%mod)*(len1%mod);
84     temp4%=mod;
85     temp1%=mod;
86     ans+=temp1+temp4;
87     ans%=mod;
88     cout<'\n';
89 
90 
91 
92 }
View Code

 

这种1~n的排列  尽量往等差数列求和的方向去想

题解的做法是直接求出所要求的范围内的奇数和偶数的个数  然后由等差数列  前n个奇数的和为n^2 前n个偶数的和为n*(n+1)  

答案即为F(r)-F(l-1)   取模要注意每个地方都要取到, 不然很容易出负数

 1 #include
 2 using namespace std;
 3 #define ll long long
 4 #define pb push_back
 5 const int maxn =2e5+10;
 6 const int mod=1e9+7;
 7 
 8 ll cal(ll x)
 9 {
10     ll odd=0,even=0,f=1,sum=1;
11     while(x-sum>=0)
12     {
13         x-=sum;
14         if(f%2)
15         {
16             odd+=sum;
17         }
18         else
19             even+=sum;
20         sum*=2;
21         f++;
22     }
23     if(f%2)
24         odd+=x;
25     else
26         even+=x;
27     return ((odd%mod*(odd%mod))%mod+(even%mod*((even+1)%mod))%mod)%mod;
28 }
29 
30 
31 int main()
32 {
33     ios::sync_with_stdio(false);
34     cin.tie(0);
35     ll l,r;
36     cin>>l>>r;
37     ll ans=cal(r)-cal(l-1);
38     ans=(ans+mod)%mod;
39     cout<'\n';
40 
41 
42 }
View Code

 

你可能感兴趣的:(Codeforces Round #553 (Div. 2) C. Problem for Nazar)