zoukankan      html  css  js  c++  java
  • FOI2019算法冬令营D1

    A. 全连

    1s,256MB
    E.Space 喜欢打音游。
    但是他技术不好,总是拿不到全连(Full Combo)。
    现在他面前有一份乐谱,乐谱的其中一段有 nnn个连续的单键音符。
    相邻两个音符的到来时间均相等,我们可以认为第 iii 个音符会在第 iii 个时刻到来。
    点击一个音符,E.Space 需要一段准备时间来进行移动手指之类的操作。由于音符的位置和周围情况不同,点击每个音符的准备时间也不同。
    在一个音符的准备时间内,E.Space 没法做到去点击其它音符,但是不同音符的准备时间范围可以互相重叠。形式化地,令第 iii 个音符的准备时间为 ti​t_i​ti​ 个单位时间,那么如果 E.Space 选择去点击第 iii 个音符,那么他就没法点击所有到来时刻在 (i−ti,i+ti​​)(i − t_i ,i + t_i​​)(iti,i+ti) 中的音符。
    为了获得更高的分数,E.Space 还计算了每个音符的性价比aia_iai。一个音符的性价比等于点击这个音符得到的分数除以 E.Space 点击它所需要的准备时间。
    E.Space 就不指望全连了,他只是想让你帮他计算一下他最多可以得到多少分数。
    n&lt;=1e6,ai&lt;=1e9n&lt;=1e6,a_i&lt;=1e9n<=1e6,ai<=1e9

    题解

    大大的良心题啊
    很好想到dp:fif_ifi表示前iii个数,iii为最后一个取的最高得分
    显然fi=fj+ai∗tif_i=f_j+a_i*t_ifi=fj+aiti
    其中j+tj&lt;=i,i−ti&gt;=jj+t_j&lt;=i,i-t_i&gt;=jj+tj<=i,iti>=j
    所以我们可以写个堆,里面的元素以x+txx+t_xx+tx排序
    当计算fif_ifi的时候,就可以把堆里面小于iii的元素弹出,将其dp值插入到线段树中,然后就是区间查找最大值
    上代码

    #include <cstdio>
    #include <queue>
    #include <algorithm>
    #define Ls k<<1
    #define Rs k<<1|1
    #define mid ((l+r)>>1)
    #define LL long long
    using namespace std;
    const int N=1e6+5;
    int n,t[N];LL f[N],ax[N*4],ans;
    struct O{
    	int x;
    	friend bool operator < (const O& A,const O& B){
    		return A.x+t[A.x]>B.x+t[B.x];
    	}
    };
    priority_queue<O>q;
    void update(int k,int l,int r,int x,LL v){
    	if (l==r){ax[k]=v;return;}
    	if (mid>=x) update(Ls,l,mid,x,v);
    	else update(Rs,mid+1,r,x,v);
    	ax[k]=max(ax[Ls],ax[Rs]);
    }
    LL query(int k,int l,int r,int L,int R){
    	if (L>R) return 0;
    	if (L<=l && r<=R) return ax[k];
    	if (mid<L) return query(Rs,mid+1,r,L,R);
    	if (mid>=R) return query(Ls,l,mid,L,R);
    	return max(query(Ls,l,mid,L,R),query(Rs,mid+1,r,L,R));
    }
    int main(){
    	freopen("fc.in","r",stdin);
    	freopen("fc.out","w",stdout);
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++) scanf("%d",&t[i]);
    	for (int i=1;i<=n;i++){
    		LL x;scanf("%lld",&x);f[i]=x*t[i];
    		while(!q.empty()){
    			O k=q.top();if (k.x+t[k.x]>i) break;
    			q.pop();update(1,1,n,k.x,f[k.x]);
    		}
    		f[i]+=query(1,1,n,1,i-t[i]);
    		ans=max(ans,f[i]);q.push((O){i});
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    B. 原样输出

    3s,256MB
    nealchen 是一只 copycat。
    它会把输入按行读入,原封不动地复制到输出中去。
    但是在一次更新以后,它的程序出了一些问题。
    它没法输出换行符了。
    并且,读入的时候,总会莫名其妙地随机漏掉开头和结尾的若干个字符,甚至整行都会漏掉。
    比如 orznight 可能会变成 rzni ,orz,h 或者空串。
    现在你找到一份输入文件丢给 nealchen,你想知道它的输出可能有多少种情况,以及每种情况分别是什么。
    由于你找到的输入文件全部来自之前的福建省选,所以所有的输入文件每行只可能包含 A,C,G,T 四种字符。
    保证输入文件大小不超过 1MB ,保证输出文件大小不超过 200MB 。

    题解

    如果只有一个串,就是后缀自动机的基本应用
    假设我们在匹配一个字符串能否成为答案,那我们就是贪心的匹配
    所以我们从后往前建n个后缀自动机,然后在建立第i个SAM的时候看每个点是不是都有ACGT的出边,如果没有的话,那就往i+1的rt的对应出边节点连边
    然后得到一个拓扑图,可以dp出答案,输出方案就直接dfs
    上代码

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int N=3e6+5,P=1e9+7;
    int d[N],ans,sz,lst,k,n,m[N],las[4],rt[N],in[N];
    string s[N];queue<int>q;vector<int>gg[N];char g[N];
    struct SAM{int len,link,mp[4];}sam[N];
    void sam_con(int d,int ch){
    	int np=++sz,p=lst;
    	sam[np].len=sam[p].len+1;
    	while(p && !sam[p].mp[ch])
    		sam[p].mp[ch]=np,p=sam[p].link;
    	if (!p) sam[np].link=rt[d];
    	else{
    		int q=sam[p].mp[ch];
    		if (sam[q].len==sam[p].len+1)
    			sam[np].link=q;
    		else{
    			int nq=++sz;
    			sam[nq].len=sam[p].len+1;
    			sam[nq].link=sam[q].link;
    			for (int i=0;i<4;i++)
    				sam[nq].mp[i]=sam[q].mp[i];
    			sam[q].link=sam[np].link=nq;
    			while(p && sam[p].mp[ch]==q)
    				sam[p].mp[ch]=nq,p=sam[p].link;
    		}
    	}
    	lst=np;
    }
    void dfs(int id,int x,int j){
    	if (j==0) g[x]='A';if (j==1) g[x]='C';
    	if (j==2) g[x]='G';if (j==3) g[x]='T';
    	for (int i=0;i<=x;i++)
    		putchar(g[i]);putchar('
    ');
    	for (int i=0;i<4;i++)
    		if (sam[id].mp[i])
    			dfs(sam[id].mp[i],x+1,i);
    }
    int main(){
    	freopen("copy.in","r",stdin);
    	freopen("copy.out","w",stdout);
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    		cin>>s[i],m[i]=s[i].length();
    	for (int i=n;i;i--){
    		lst=++sz;rt[i]=sz;
    		for (int y,j=0;j<m[i];j++){
    			if (s[i][j]=='A') y=0;
    			if (s[i][j]=='C') y=1;
    			if (s[i][j]=='G') y=2;
    			if (s[i][j]=='T') y=3;
    			sam_con(i,y);
    		}
    		for (int j=rt[i];j<=sz;j++)
    			for (int l=0;l<4;l++){
    				if (!sam[j].mp[l])
    					sam[j].mp[l]=las[l];
    				if (sam[j].mp[l])
    					gg[sam[j].mp[l]].push_back(j),
    					in[j]++;
    			}
    		for (int l=0;l<4;l++)
    			if (sam[rt[i]].mp[l])
    				las[l]=sam[rt[i]].mp[l];
    	}
    	scanf("%d",&k);
    	if (k){
    		puts("");ans++;
    		for (int i=0;i<4;i++)
    			if (sam[rt[1]].mp[i])
    				dfs(sam[rt[1]].mp[i],0,i);
    	}
    	for (int i=1;i<=sz;i++){
    		d[i]=1;
    		if (!in[i]) q.push(i);
    	}
    	while(!q.empty()){
    		int x=q.front();q.pop();
    		for (int j,i=gg[x].size()-1;~i;i--){
    			j=gg[x][i];(d[j]+=d[x])%=P;in[j]--;
    			if (!in[j]) q.push(j);
    		}
    	}
    	printf("%d
    ",d[rt[1]]);
    	return 0;
    }
    

    C. 不同的缩写

    1s,256MB
    你在写一款 Galgame 的剧情(的代码)。
    在这个游戏中一共有 n 个角色。你需要编写一些关于这些角色的对话内容。然而,在写这些对话内容之前,都要写一段关于角色信息的代码,就像这样:
    Character(“Alex”, color = “#FFFC3A”)
    你觉得这样好麻烦。你决定把它简化一下。你打算用角色名字的一个非空子序列(可以不连续)来作为它的简称。
    当然,不同的角色要用不同的字符串作为简称,否则你就变量重名了。
    你想确定一个简称的分配方案使得所有角色中最长的简称尽量短,这样你打起代码就会方便一些。
    n,len<=300

    题解

    首先二分答案mid,然后对于每个串,找出长度<=mid的子序列
    注意:当找出n个子序列的时候就可以不用找了,因为这n个中肯定有一个可以作为答案
    那我们就对找到的子序列建点,和字符串下标i连边,然后跑二分图匹配,如果满流则为合法
    复杂度玄学,上代码

    #include <bits/stdc++.h>
    #define LL unsigned long long
    #define K 793999
    using namespace std;bool G;
    const int N=333,M=444444;
    int n,Ax,l=1,r,g[N],cp,nex[M],d[M];
    int S,T,head[M],cur[M],V[M],W[M],t,dd[M];
    char s[N][N];LL h[M],gg;string H[M],ggg,ys[M];
    map<LL,int>p,q;queue<int>Q;
    inline void ins(int u,int v){
    	V[++t]=v;W[t]=1;nex[t]=head[u];head[u]=t;
    	V[++t]=u;W[t]=0;nex[t]=head[v];head[v]=t;
    }
    inline bool bfs(){
    	for (int i=S;i<=T;i++) d[i]=-1;
    	Q.push(S);d[S]=0;
    	while(!Q.empty()){
    		int x=Q.front();Q.pop();
    		for (int i=head[x];i;i=nex[i])
    			if (d[V[i]]==-1 && W[i]) 
    				d[V[i]]=d[x]+1,Q.push(V[i]);
    	}
    	return d[T]>-1;
    }
    int dfs(int x,int ax){
    	if (x==T) return ax;
    	int sum=0,tt;
    	for (int& i=cur[x];i;i=nex[i]){
    		if (W[i] && d[V[i]]==d[x]+1
    		 && (tt=dfs(V[i],min(ax,W[i]))))
    			ax-=tt,W[i]-=tt,W[i^1]+=tt,sum+=tt;
    		if (!ax) break;
    	}
    	return sum;
    }
    inline void work(int d,int x){
    	for (int j=1,i=1;i<=g[d];i++)
    		for (int k=j;k;k--){
    			if (dd[k]==x) continue;
    			gg=h[k]*K+s[d][i];
    			if (G) ggg=H[k]+s[d][i];
    			if (q[gg]!=d){
    				h[++j]=gg,q[gg]=d;
    				dd[j]=dd[k]+1;
    				if (G) H[j]=ggg;
    				if (!p[gg]){
    					p[gg]=++cp;
    					if (G) ys[cp]=ggg;
    				}
    				ins(d,p[gg]+n);
    			}
    			if (j==n+1) return;
    		}
    }
    inline bool J(int x){
    	t=1;p.clear();cp=0;q.clear();
    	for (int i=S;i<=T;i++) head[i]=0;
    	for (int i=1;i<=n;i++)
    		ins(S,i),work(i,x);
    	T=cp+n+1;
    	for (int i=1;i<=cp;i++) ins(i+n,T);
    	int sum=0;while(bfs()){
    		for (int i=S;i<=T;i++)
    			cur[i]=head[i];
    		sum+=dfs(S,1e9);
    	}
    	if (G)
    		for (int i=1;i<=n;i++)
    			for (int j=head[i];j;j=nex[j])
    				if (V[j] && !W[j]){
    					int ll=ys[V[j]-n].length();
    					for (int l=0;l<ll;l++)
    						putchar(ys[V[j]-n][l]);
    					putchar('
    ');break;
    				}
    	return sum==n;
    }
    int main(){
    	freopen("diff.in","r",stdin);
    	freopen("diff.out","w",stdout);
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    		scanf("%s",s[i]+1),
    		g[i]=strlen(s[i]+1),
    		Ax=max(Ax,g[i]);
    	r=Ax+1;while(l<r){
    		int mid=(l+r)>>1;
    		if (J(mid)) r=mid;
    		else l=mid+1;
    	}
    	if (l>Ax) puts("-1");
    	else{
    		printf("%d
    ",l);G=1;
    		return !J(l);
    	}
    	return 0;
    }
    
  • 相关阅读:
    信息收集渠道:文本分享类网站Paste Site
    泛域名Wildcard Domain
    分享Kali Linux 2017年第12周镜像文件
    同源策略Same-origin policy
    Wireshark如何选择多行
    GPP加密破解工具gpp-decrypt
    HTTP基础认证Basic Authentication
    HAXM 6.0.5显示不兼容Windows
    分享Kali Linux 2017年第11周镜像文件
    bitShark对Android版本的支持
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/10544701.html
Copyright © 2011-2022 走看看