Codeforces1600数学day5[找规律CodeForces - 1059C,贪心数学A - Banh-mi CodeForces - 1062C ]

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) (m1)个数加上 n n n贡献就是 n ∗ ( m − 1 ) n*(m-1) n(m1),很明显的贪心每次都选最大的数贡献就是最大的
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)?(n1):n}
a { 2 ∗ 1 , 2 ∗ 2 , 2 ∗ 3......2 ∗ n } a\{2*1,2*2,2*3......2*n\} a{21,22,23......2n}
同理继续把奇数乘项删掉
**
这样我们就把问题转化成了一个长度为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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值