专栏文章

题解:P14406 [JOISC 2015] 愉快的标志设计 / En-JOI-able Logo Design

P14406题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@min4kb2k
此快照首次捕获于
2025/12/01 20:28
3 个月前
此快照最后确认于
2025/12/01 20:28
3 个月前
查看原文
比较小清新的题目。
发现题目给出的序列很明显就是由 44 个更小的序列组合而来的,所以我们自然而然的想到递归搜索
不难发现,对于前 33 个小序列,代价都是一样的算法,只要看有多少个合法的,再用区间长度减去就行了。
但是对于最后一种序列,我们发现和当前处理的序列是属于同一种类型,但是问题规模更小。所以对于最后一种序列我们递归求解就好了。
分析时间:求解前 33 种序列可以用前缀和预处理,这里是 Θ(1)\Theta(1) 的。对于递归求解部分,明显和递归深度有关,每次递归深度减一,规模变为原先的 14\frac{1}{4},总共就是 Θ(k)\Theta(k) 的时间。所以单次求解的时间复杂度就是 Θ(k)\Theta(k)
因为可以从任意起点出发,我们破环成链,预处理前缀和,再枚举起点,总共枚举 Θ(4k)\Theta(4^k) 次,单次 Θ(k)\Theta(k),总复杂度就是 Θ(4k×k)\Theta(4^k\times k) 的,可以通过。

代码

CPP
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define V vector
#define FOR(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define pb push_back
const int INF=1e9+10;
signed main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int k;cin>>k;
	string s;cin>>s;
	int n=(1<<(2*k));
	V<int>num(2*n+1),sumj(2*n+1,0),sumo(2*n+1,0),sumi(2*n+1,0);
	FOR(i,1,n) num[i]=num[i+n]=s[i-1];
	FOR(i,1,2*n){
		sumj[i]=sumj[i-1]+(num[i]=='J');
		sumo[i]=sumo[i-1]+(num[i]=='O');
		sumi[i]=sumi[i-1]+(num[i]=='I');
	}
	function<int(int,int)>dfs=[&](int dep,int l){
		if(dep==0) return 0;
		int l1=l+(1<<(2*(dep-1))),l2=l1+(1<<(2*(dep-1))),l3=l2+(1<<(2*(dep-1)));
		int ans1=sumj[l1-1]-sumj[l-1];
		int ans2=sumo[l2-1]-sumo[l1-1];
		int ans3=sumi[l3-1]-sumi[l2-1];
		return l3-l-(ans1+ans2+ans3)+dfs(dep-1,l3);
	};
	int ans=INF;
	FOR(i,1,n){
		ans=min(ans,dfs(k,i));
	}
	cout<<ans;
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...