首页 > 其他分享 >题解:P10279 [USACO24OPEN] The 'Winning' Gene S

题解:P10279 [USACO24OPEN] The 'Winning' Gene S

时间:2024-08-20 13:26:50浏览次数:5  
标签:tmp 子串 now int 题解 void st USACO24OPEN Gene

思路

建议升蓝。

算法一

考虑暴力。

我们先枚举 \(K,L\),考虑如何求解。

直接枚举每一个 \(K\)-mer,再枚举里面的每一个长度为 \(L\) 的子串,找到最大的子串并在起始部分打一个标记。最后直接看有几个地方被打标记就行。

时间复杂度:\(O(n^4)\)。预计能过测试点 \(1-4\)。

算法二

我们可以把选取子串的过程大概画下来。

我们发现每一次都会往后面都会多一个子串,我们可以考虑一个数据结构,可以删除最前面的数据,而且可以往后面加入一个数据,并动态求最值。我在这里选择的数据结构为单调队列

时间复杂度:\(O(n^3)\),预计能过测试点 \(1-7\)。

代码

实践后:

常数写大了,超了 0.07秒

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long
namespace gtx{
//	Fast IO
	void read(int &x){
		x = 0;int h = 1;char tmp;
		do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
		while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
		x*=h;
	}
	void read(char &x){do{x=getchar();}while(x==' '||x=='\n'||x=='\r');}
	void write(char x){putchar(x);}
	void write(int x){
		if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
		do{st[++tot]=x%10,x/=10;} while(x);
		while(tot){putchar(st[tot--]+'0');};
	}
	void write(int x,char y){write(x);write(y);}
	const int MAXN = 3100;
	int n,ans,t[MAXN];
	char a[MAXN];
	signed main(){
		read(n);
		for(int i = 1;i<=n;i++) read(a[i]);
		for(int K = 1;K<=n;K++){
			for(int L = 1;L<=K;L++){
				deque<pair<int,string>> st;
				string now;
				for(int i = 1;i<=L;i++) now += a[i];
				st.push_back({1,now});
				for(int i = 2;i<=K-L+1;i++){
					now.erase(now.begin());
					now += a[i+L-1];
					while(!st.empty()&&st.back().second>now) st.pop_back();
					st.push_back({i,now});
				}
				bitset<MAXN> b;
				b.set(st.front().first);
				for(int i = K-L+2;i<=n-L+1;i++){
					if(st.front().first==i-(K-L)-1) st.pop_front();
					now.erase(now.begin());
					now += a[i+L-1];
					while(!st.empty()&&st.back().second>now) st.pop_back();
					st.push_back({i,now});
					b.set(st.front().first);
				}
				t[b.count()]++; 
			}
		}
		for(int i = 1;i<=n;i++) write(t[i],'\n');
		return 0;
	}
}
signed main(){
//	freopen("gene.in","r",stdin);
//	freopen("gene.ans","w",stdout);
//	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int T = 1;
//	gtx::read(T);
	while(T--) gtx::main();
	return 0;
}

算法三

我们在上面的代码中发现其实 \(K\) 有没有都几乎没有什么区别,于是可以想一想定长的 \(L\) 可以对哪些答案产生的贡献。

记录前面第一个比这个子串大的子串的起始位置为 \(left_i\),后面第一个比这个子串大的子串的起始位置为 \(right_i\)。那么对于一个子串来说,如果这个子串能产生贡献 \(K\) 最大应该的值的区间应该是这样的:

所以产生的最大的 \(K\) 为 \(right_i+L-2-left_i\)。最小的 \(K\) 应该就是这个子串的长度,那么这个子串就会对这些 \(K\) 产生答案。我们可以用差分解决。

至于维护 \(left_i\) 和 \(right_i\) 可以使用单调队列

时间复杂度:\(O(n^2)\)。预计得分:\(100pts\)。

AC代码

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long
namespace gtx{
//	Fast IO
	void read(int &x){
		x = 0;int h = 1;char tmp;
		do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
		while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
		x*=h;
	}
	void read(char &x){do{x=getchar();}while(x==' '||x=='\n'||x=='\r');}
	void write(char x){putchar(x);}
	void write(int x){
		if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
		do{st[++tot]=x%10,x/=10;} while(x);
		while(tot){putchar(st[tot--]+'0');};
	}
	void write(int x,char y){write(x);write(y);}
	const int MAXN = 3100;
	int n,t[MAXN],ans[MAXN][MAXN],left[MAXN],right[MAXN];
	char a[MAXN];
	signed main(){
		read(n);
		for(int i = 1;i<=n;i++) read(a[i]);
			for(int L = 1;L<=n;L++){
				stack<pair<int,string>> st;
				string now;
				for(int i = 1;i<=L;i++) now += a[i];
				st.push({1,now});
				for(int i = 1;i<=n-L+1;i++) left[i] = 0;
				for(int i = 1;i<=n-L+1;i++) right[i] = 0;
				left[1] = 1;
				for(int i = 2;i<=n-L+1;i++){
					now.erase(now.begin());
					now += a[i+L-1];
					while(!st.empty()&&st.top().second>now) st.pop();
					left[i] = st.empty()?1:st.top().first+1;
					st.push({i,now});
				}
				while(!st.empty()) st.pop();
				now="";
				for(int i = n-L+1;i<=n;i++) now+=a[i];
				right[n-L+1] = n;
				st.push({n-L+1,now});
				for(int i = n-L;i>=1;i--){
					now.erase(--now.end());
					now = a[i]+now;
					while(!st.empty()&&st.top().second>=now) st.pop();
					right[i] = st.empty()?n:st.top().first+L-2;
					st.push({i,now});
				}
				for(int i = 1;i<=n-L+1;i++){
					if(right[i]-left[i]+1<L) continue;
					ans[L][L]++;
					ans[right[i]-left[i]+2][L]--;
				}
//				cout << L << endl;
//				for(int i = 1;i<=n;i++) cout << left[i] << " " << right[i] << endl;
			}
		for(int j = 1;j<=n;j++){
			for(int i = j;i<=n;i++){
				ans[i][j] += ans[i-1][j];
				t[ans[i][j]]++;
			}
		}
		for(int i = 1;i<=n;i++) write(t[i],'\n');
		return 0;
	}
}
signed main(){
//	freopen("gene.in","r",stdin);
//	freopen("gene.out","w",stdout);
//	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int T = 1;
//	gtx::read(T);
	while(T--) gtx::main();
	return 0;
}

tag

USACO
单调栈思维单调队列差分

标签:tmp,子串,now,int,题解,void,st,USACO24OPEN,Gene
From: https://www.cnblogs.com/gutongxing/p/18369296

相关文章

  • [题解]P4052 [JSOI2007] 文本生成器
    P4052[JSOI2007]文本生成器正难则反,我们发现用总字符串个数\(26^m\),减去不可读的字符串个数,就是答案。要使一个字符串不可读,就不能让任何模式串在其中出现。如果某个主串的第\(i\)位与自动机的节点\(j\)相匹配,那么如果状态\(j\)包含模式串(即有一个前缀是一个模式串),那么不管主......
  • 关系代数、函数依赖、Armstrong公理及软考试题解析
    注:本文面向于软考高级—系统架构设计师,具体来说是数据库部分,知识点偏零碎化。想要系统学习数据库原理的,可考虑去看《数据库原理》,清华大学出版社或其他出版社皆可。概述概念关系,就是二维表。特性:列不可分性:关系中每一列都是不可再分的属性,即不能出现如下复合属性行列无序性:......
  • P1543 [POI2004] SZP 题解
    P1543[POI2004]SZP题解传送门。题目简述有\(n\)个人,每个人都会监视另一个人,要求选出尽可能多的同学,使得选出的每一名同学都必定会被监视到。且选出的同学不可再监视其他人。思路简述因为任意一个人只能被另一个人管,那么就想到,如果没人管的同学就不能被选(不被监视)。若某......
  • 题解:[TJOI2018] 游园会
    所谓dp套dp,实际上就是在说求解一个dp的过程中,我们用另一个dp求解出他应该从某个状态转移到另一个状态。考虑一下这道题,首先求LCS的dp如下:\[dp_{i,j}=\max\{dp_{i-1,j},dp_{i,j-1},dp_{i-1,j-1}+[s_i==t_j]\}\]显然,当\(i\)固定的时候,\(dp_{i,j}\)是单调不降的,且相邻两......
  • 【LGR-196-Div.4】洛谷入门赛 #26 题A - H 详细题解--优化思路简洁代码(C++,Python语
    前言:    觉得这个比赛很有意思的,都是暴力题,涉及一些细节,难度比较适合刚学编程语言的,可以很好的锻炼基础还有手速,最后两题也是比较有意思,之后也准备更新atc的比赛题解和洛谷的一些高质量比赛题解(算法网瘾就是想参加各种比赛)   如果觉得有帮助,或者觉得我写的好,......
  • [NOI]2024 登山 题解
    好像在洛谷题解区里还没人和我做法一样,,?考场做法,只用到了倍增和线段树,感觉挺好写。考场上从开题到过题只用了2h。最底下有省流版(?)。以下是我考场里比较详细的思路,所以比较长。先考虑如何\(O(n^2)\)做,然后再想优化。容易先想到一个状态数是\(O(n^2)\)的DP,即记录起点,并将向......
  • AGC002 题解
    目录A-RangeProductB-BoxandBallC-KnotPuzzleA-RangeProduct分情况讨论:\(a\le0\leb\)时,乘积一定为\(0\);否则:\(0<a\leb\)时,乘积一定为正;否则,负数的个数有\(b-a+1\)个,判断这个数是否为奇数,若是,乘积为负,否则为正。#include<bits/stdc++.h......
  • ControlNeXt: Powerful and Efficient Control for Image and Video Generation(2024,
    ControlNeXt:PowerfulandEfficientControlforImageandVideoGeneration(2024,8)paperGithub进一步在ControlNet上进行了改进,主要针对一下两点对于每一个模块添加一个Zero-Conv也会占用很多显存.Zero-Conv两个模态的输出的mean、var具有差异,导致收敛很慢.针对1,......
  • P10423题解
    P10423[蓝桥杯2024省B]填空问题先贴上答案#include<iostream>usingnamespacestd;intmain(){stringans[]={"1204","1100325199.77",};charT;cin>>T;cout<<ans[T-'A']......
  • P10155题解
    1题意给定一个排列ppp,每次可以选择一个数pi......