codeforces round #347 div2 B rebus 贪心 + 二分

/*
    题目描述:给定一个形式如? + ? - ? + ? + ? = n的字符串,在每个?的位置填入1——n中的某一个数,使这个等式成立,
            问这样的等式是否存在,如果存在,输出将?替换成具体数字后的字符串

    思路:假设一共加了add个数,减掉了minus个数,那么这个算式能组合出的数的范围就是[ max(0 , add - n * minus) , add * n - minus],
        如果n在这个范围内的话,则一定有解,然后二分出所有加上的数的总和ans1,所有减掉的数的总和ans2;每次遇到
        加号的时候,就加上一个尽可能大的数(既不超过n,也不能因为加上了他而使得后面的加号后没有数可加),遇到
        减号时同理,按照这个规则替换掉所有的?即可
*/
#pragma warning(disable:4786)
#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<cmath>
#include<string>
#include<sstream>
#define LL long long
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define lson l,m,x<<1
#define rson m+1,r,x<<1|1
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps=1e-6;
const int maxn = 1e4 + 5 ;
char s[maxn] ;
LL n , maxv , minv ;
LL add_max , add_min , minus_max , minus_min ;
int bsearch(int left , int right , int & ret ) //返回值为加上的所有数的总和ans1,参数ret为减去所有数的总和ans2
{
    int mid  ;
    while(left <= right){
        mid = left + (right - left) / 2 ;
        if( mid - n < minus_min  ){             //mid - n为需要减去的数的和,如果比能减去的数的最小值还要小,说明mid取小了
            left = mid + 1 ;
        }
        else if( mid - n > minus_max){
            right = mid - 1 ;
        }
        else{
            ret = mid - n ;
            return mid ;
        }
    }
}
int main()
{
    char ch ;
    int cnt = 0  ;
    LL add = 0 , minuss = 0 ;
    while(scanf("%c",&ch)== 1 && ch != '='){
        if(ch == '+')   ++add;
        else if(ch == '-')  ++minuss ;
        s[cnt++] = ch ;
    }
    s[cnt] = 0;
    scanf("%lld",&n);
    ++add ;
    add_min = add   , add_max = (LL)n * add   , minus_min = minuss , minus_max = (LL)n * minuss ;
    minv = max(add_min - minus_max , (LL)0 ) ;
    maxv = add_max - minus_min ;
    if(!(minv <= n && n <= maxv)){
        printf("Impossible\n");
        return 0;
    }
    printf("Possible\n");
    int ans1 , ans2 ;
    ans1 = bsearch(add_min , add_max , ans2) ;
    int flag = 1 , len = strlen(s);
    for(int i = 0 ; i< len ; i++){
        if(s[i] == '?'){
            if(flag){
                LL res = min( n , ans1 - (add - 1 ) ) ;     //对于每个加号,可以加上的最大的值为ans1
                res = max( (LL)1 , res );
                ans1 -= res ;
                --add ;
                printf("%lld",res) ;
            }
            else{
                LL res = min( n , ans2 - (minuss - 1 ) ) ;
                res = max( (LL)1 , res) ;
                ans2 -= res ;
                --minuss ;
                printf("%lld",res) ;
            }
            continue ;
        }
        printf("%c",s[i]);
        if(s[i] == '-')     flag = 0;
        else  if(s[i] == '+')   flag = 1 ;
    }
    printf("= %lld\n",n);
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值