6692. 【2020.06.05省選模擬】靈符「無壽之夢」

題目

有一個由*+組成的字符串,*表示乘22++表示加11
選出一個子序列,使得子序列形成的數字模2k2^k最大
n,k1e6n,k\leq 1e6


思考歷程

我又把“子序列”看成了“子串”……
到最後幾十分鐘寫暴力的時候,我才發現這一點……
於是最終不加思考地寫了個狀壓DP上去。
沒來得及改回來,開了1e610241e6*1024的數組,編譯竟然過了???
於是就爆00了。


正解

如果子序列中選擇有*++,其實它等價於+*
於是可以做如下轉化:在原字符串中,如果遇到長度大於22+段,就將它兩個兩個地丟到上一個*前,直到長度爲1122(保留22個是爲了保留它只選擇一個的權利)。
注意一開始在序列前面加上無限個*,顯然這對答案沒有影響。

於是字符串中的+段就只剩下長度爲11的和長度爲22的。
貪心地從前往後欽定,*用來保證位數,+用來填11
*足夠的時候,肯定是儘量地在高位處填11。並且這個時候不要進位,因爲保證了高位儘量填,進位會導致前功盡棄。
這樣一直填到*不夠的時候,就將剩下的整個字符串都加進來。這時候可以有進位,但每一位最多隻可能進一位,並且不可能進到之前儘量填11的部分。

於是這題就做完了。


代碼

有一說一這題用指針打特別爽。

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1000010
int n,K;
char str[N];
struct Node{
	Node *pre,*suc;
	bool op;
	int w;
	int rem;
};
Node *fir,*lst;
int ans[N];
int main(){
	freopen("dream.in","r",stdin);
	freopen("dream.out","w",stdout);
	scanf("%d%d%s",&n,&K,str+1);
	for (int i=1;i<=n;++i)
		str[i]=(str[i]=='+');
	lst=fir=new Node;
	*fir={NULL,NULL,0,1000000000};
	for (int i=1,cnt=0;i<=n;++i)
		if (lst->op==str[i])
			lst->w++;
		else{
			Node *nw=new Node;
			*nw={lst,NULL,(bool)str[i],1};	
			lst->suc=nw;
			lst=nw;
		}
	for (Node *p=lst;p;p=p->pre)
		if (p->op==1 && p->w>2){
			int d=(p->w&1?p->w-1>>1:p->w-2>>1);
			p->w-=d*2;
			if (p->pre->w==1)
				p->pre->pre->w+=d;
			else{
				Node *nw1=new Node,*nw2=new Node;
				*nw1={p->pre,nw2,1,d};
				*nw2={nw1,p,0,1};
				p->pre->w--;
				p->pre->suc=nw1;
				p->pre=nw2;
			}
		}
	int cntplus=lst->op;
	lst->rem=(lst->op==0?lst->w:0);
	for (Node *p=lst->pre;p;p=p->pre){
		cntplus+=p->op;
		p->rem=p->suc->rem+(p->op==0?p->w:0);
	}
	if (cntplus>=K){
		for (int i=0;i<K;++i)
			putchar('1');
		return 0;
	}
	int i=K;
	for (Node *p=fir;p;p=p->suc)
		if (p->op){
			if (p->rem>=i-1)
				ans[--i]=1;	
			else
				ans[p->rem]+=p->w;
		}
	for (int i=0;i<K;++i){
		ans[i+1]+=ans[i]>>1;
		ans[i]&=1;
	}
	i=K-1;
	for (;i>=0;--i)
		if (ans[i])
			break;
	if (i<0)
		putchar('0');
	else
		for (;i>=0;--i)
			putchar(ans[i]+'0');
	return 0;
}

總結

不要總是犯把“子序列”看成“子串”這樣幼稚的錯誤啊……

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章