Missing Subsequence Sum个人理解与做法(Codeforces Round 941 (Div. 2))

这道题想了挺久的

题解

我们都知道1,2,4,8,...,2^n 能刚好凑出1~2^{n+1}-1中的所有数

要想刚好凑出1~n(2^{m}<=n<2^{m+1})中所有的数,则可以用1,2,...2^{m-1}以及n-(2^{m}-1),其中有些数可能会由两种不同的组合凑出来,但是能凑出来的数一定在1~n的范围内

思考: 一种可能能行的方法:假设2^{m-1}-1<k<=2^{m}-1先有数1,2..2^(m-2)可以凑出1~2^{m-1}-1中的所有数,数列中不能有2^{m-1 },有的话范围到了1~2^{m}-1包含了k,不符合题意,所以数列中的下一个数为k-(2^{m}-1)-1,就可刚好凑出1~k-1中的所有数,当时首先设想之后的数为2^{m},2^{m+1},2^{m+2}...直到数列凑够25个数,但是有个问题就是数列1,2..2^(m-2),k-(2^m-1)-1可以凑出1~k-1中的所有数,数列中再加上一个2^m,则能凑出的数的范围变为了1~k-1∪2^m~k-1+2^m,其中k+1~2^m-1范围内的数不能被凑出来,所以不可行.

再思考在k-(2^m-1)-1后面数列加上一个数k+1,    1,2...2^(m-2),k-(2^m-1)-1可以凑出1~k-1,再加上k+1,就可以凑出1~k-1与k+1~2k,数列后面再有2^{m},2^{m+1},2^{m+2}...,就能够实现范围的无缝衔接(因为k>=2^m,所以2k>=2^(m+1)),但是又发现了一个致命的问题 1,2...2^(m-2),k-(2^m-1)-1,k+1可以凑出1~2k(不包含k),再加上2^m并不能凑出1~2^(m+1)-1中的所有数,因为1,2...2^(m-2),k-(2^m-1)-1,k+1凑出的数不包含k,则加上2^m后的范围就不包含k+2^m,数列中再加上2^(m+1),范围内的数凑不出来k,2^m+k,2^(m+1)+k,2^m+k+2^(m+1),以此类推     1,2...2^(m-2),k-(2^m-1)-1,k+1凑出来的数不包含k而导致了一系列问题,一些与k相关的数并不能凑出来

最终解决办法:首先一样前面的数列为1,2...2^(m-2),k-(2^m-1)-1可以凑出来1~k-1,然后数列加上一个数据k+1则可以凑出来1~k-1∪k+1~2k 数列中再加上数据2k+1,则可以凑出来1~k-1∪k+1~4k+1,但是不包含3k+1,  数列中再加上数3k+1,则可以凑出来1~k-1∪k+1~7k+2其中凑不出来6k+2,  则数列中加上6k+2 凑不出来12k+4, 以此类推,除了前两个数都是前一个数的二倍,凑出来25个数

代码

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;

int a[50];
int main(){
    int T;
    cin>>T;
    while(T--){
        int n,k;
        cin>>n>>k;
        int cnt=1;
        int sum=0;
        int t=1;
        if(k==1){
            a[1]=2;
            a[2]=3;
            cnt=3;
            sum=5;
            t=4;
        }
        
        while(cnt<=25){
            
            if(sum<k&&sum+t>=k){
                // cout<<k<<' '<<sum<<endl;
                a[cnt]=k-sum-1;
                sum+=a[cnt];
                cnt++;
                a[cnt]=k+1;
                sum+=a[cnt];
                cnt++;
                a[cnt]=2*k+1;
                cnt++;
                t=3*k+1;
                break;
            }else if(t>a[cnt-1]){
                a[cnt]=t;
                sum+=a[cnt];
                cnt++;
            }
            t*=2;
            
        }
        while(cnt<=25){
            a[cnt++]=t;
            t*=2;
        }
        cout<<25<<endl;
        for(int i=1;i<=25;i++)cout<<a[i]<<' ';
        cout<<endl;
 
    }
}

  • 11
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值