A - Banh-mi CodeForces - 1062C
题目大意:就是开始给你一个01序列,和q次询问,每次询问会给你一个区间,每次你会从这个区间内拿出一个数,在区间内的其他未被拿走的数字会加上这个数的数值,问你以什么顺序拿可以使得拿走的数 s u m sum sum最大
解题思路:1.假设询问选取的区间是
[
l
,
r
]
[l,r]
[l,r]里面有
m
m
m个数,假如说我我们把某个数
n
n
n拿出来那么里面就有每个
(
m
−
1
)
(m-1)
(m−1)个数加上
n
n
n贡献就是
n
∗
(
m
−
1
)
n*(m-1)
n∗(m−1),很明显的贪心每次都选最大的数贡献就是最大的
2.假如说
[
l
,
r
]
[l,r]
[l,r]区间内有
x
x
x个1,有
y
y
y个0,那么我们就是先选每个1出现的位置。
举个例子0011,
s
u
m
=
1
+
2
+
3
+
6
sum = 1 + 2 + 3 +6
sum=1+2+3+6
#include <iostream>
#include <cstdio>
#include <stack>
#include <sstream>
#include <vector>
#include <map>
#include <cstring>
#include <deque>
#include <cmath>
#include <iomanip>
#include <queue>
#include <algorithm>
#include <set>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define _for(i,a,b) for( int i = (a); i < (b); ++i)
#define _rep(i,a,b) for( int i = (a); i <= (b); ++i)
#define for_(i,a,b) for( int i = (a); i >= (b); -- i)
#define rep_(i,a,b) for( int i = (a); i > (b); -- i)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define hash Hash
#define next Next
#define count Count
#define pb push_back
#define f first
#define s second
using namespace std;
const int N = 1e5+10, mod = 1e9 + 7;
const double eps = 1e-10;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
inline LL read()
{
LL f=1,s=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
return s*f;
}
char a[N];
LL n, m;
LL pre[N];
LL square[N];
LL b = 1;
LL slove(int be, int end)
{
LL res = 0;
LL numone = pre[end] - pre[be - 1];
LL numzero = end - be + 1 - numone;
// cout << numone << " " << numzero << endl;
if(numone) res += square[numone - 1] % mod;
if(numzero) res += res * square[numzero - 1];
return res % mod;
}
int main()
{
square[0] = 1;
_for(i,1,N)
{
square[i] = (b * 2 + square[i - 1]) % mod;
b = (b * 2) % mod;
}
cin >> n >> m;
cin >> a+1;
_for(i,1,n+1)
{
if(a[i] == '1') pre[i] = pre[i - 1] + 1;
else pre[i] = pre[i - 1];
}
while(m--)
{
int l, r;
cin >> l >> r;
cout << slove(l,r) << endl;
}
return 0;
}
B - Sequence Transformation CodeForces - 1059C
题目大意:给你一个
n
n
n然后代表
1
1
1到
n
n
n的一个序列
然后说每次进行一种操作 序列当前所有数的
g
c
d
gcd
gcd然后把
g
c
d
gcd
gcd结果加入一个答案数组 然后此时可以删除序列中的一个数
重复这种操作 直至序列没有数 同时保证答案序列是字典序最大 前面的数越大越好
解题思路:1.首先有一个显而易见的结论:对于任意排列,b序列中的前n/2个数总是1。原因是相邻的两个数互质。
2.现在我们来考虑一个长度大于3的排列,怎样才能将b序列的字典序最大。
根据字典序的定义,我们需要最大化每一次进入队列的
g
c
d
gcd
gcd
即,当前最大就是整体最好的选择。
那么我们对于任意两个相邻的数,都有一个选择:删除其中的奇数或删除其中的偶数。
我们应该全部删除奇数或者全部删除偶数,不然就会有两个数相邻,从而出现
g
c
d
=
1
gcd=1
gcd=1使得答案不优。
如果我们删除偶数,我们就会发现有
a
i
=
1
ai=1
ai=1使得这个序列的
g
c
d
=
1
gcd=1
gcd=1而使得答案不优。
所以我们对于每个序列,都要删除奇数,使得
g
c
d
∗
=
2
gcd*=2
gcd∗=2。
观察操作后的序列
a
{
2
,
4
,
6
,
8.....
(
n
&
1
)
?
(
n
−
1
)
:
n
}
a\{2,4,6,8.....(n\&1)?(n-1):n\}
a{2,4,6,8.....(n&1)?(n−1):n}
a
{
2
∗
1
,
2
∗
2
,
2
∗
3......2
∗
n
}
a\{2*1,2*2,2*3......2*n\}
a{2∗1,2∗2,2∗3......2∗n}
同理继续把奇数乘项删掉
**
这样我们就把问题转化成了一个长度为n/2的子问题。
对于1<=n<=3的序列或长度小于等于3的子问题,题目的样例就是我们想要的结果,特判即可。
复杂度实际上是O(n)的。
**
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<algorithm>
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define swap(a,b) (a=a+b,b=a-b,a=a-b)
#define maxn 320007
#define N 100000000
#define INF 0x3f3f3f3f
#define mod 1000000009
#define e 2.718281828459045
#define eps 1.0e18
#define PI acos(-1)
#define lowbit(x) (x&(-x))
#define read(x) scanf("%d",&x)
#define put(x) printf("%d\n",x)
#define memset(x,y) memset(x,y,sizeof(x))
#define Debug(x) cout<<x<<" "<<endl
#define lson i << 1,l,m
#define rson i << 1 | 1,m + 1,r
#define ll long long
//std::ios::sync_with_stdio(false);
//cin.tie(NULL);
using namespace std;
int main()
{
int n;
cin>>n;
int k=1;
while(n)
{
if(n==3)
{
cout<<k<<" "<<k<<" "<<k*3<<endl;
return 0;
}
for(int i=0; i<(n+1)/2; i++)
cout<<k<<" ";
n/=2;
k*=2;
}
return 0;
}