20190408动规考试(水货)

呃,一道都没A呃…(果然我太菜了)
简单分析一下…
1.调节音量(HLOJ#1151)
2.蛋糕塔(HLOJ#1152)
3.格斗(HLOJ#1153)
4.最大LCS(HLOJ#1154)
5.数字变换(HLOJ#1181)
(以上是考试的五道题目)

第一题

标准的送分题,暴力都能过(只是我忘了记忆化
在这里插入图片描述
数据范围
在这里插入图片描述
就dfs枚举过去吧,反正数据不大,可以过得,但千万千万别忘了要二维数祖记忆化才不会超时啊!
(GYF专用代码粘上)

#include<bits/stdc++.h>
using namespace std;
#define s1(a,n) sort(a+1,a+n+1)
#define s2(a,n) sort(a+1,a+n+1,mc)
#define ll long long
#define sg string
#define st struct
#define f1(i,l,r) for(int i=l;i<=r;++i)
#define f2(i,r,l) for(int i=r;i>=l;--i)
#define f3(i,a,b) for(int i=a;i;i=b)
#define me(a,b) memset(a,b,sizeof(a))
#define sf scanf
#define pf printf
#define fi(a) freopen(a,"r",stdin)
#define fo(a) freopen(a,"w",stdout)
#define cn continue
#define bk break
#define rt return
#define ct const
ct int maxn=1000+10;
int n,begl,maxl,c[maxn],maxx=-1,f[maxn][maxn]={};
bool mc(int x,int y){
	rt x>y;
}
void init(){
	sf("%d%d%d",&n,&begl,&maxl);
	f1(i,1,n) sf("%d",&c[i]);
}
void work(int k,int ans){
	if(k<0||k>maxl) rt;
	if(f[k][ans]==1) rt;
	f[k][ans]=1;
	if(ans==n+1){
		maxx=max(maxx,k);
		rt;
	}
	work(k+c[ans],ans+1);
	work(k-c[ans],ans+1);
}
void prin(){
	pf("%d",maxx);
}
int main(){
	fi("ChangingSounds.in");
	fo("ChangingSounds.out");
	init();
	work(begl,1);
	prin();
	rt 0;
}

(怎么宏定义又变多了!?)
(毕竟,我我我犯贱呐…)

第二题

一道背包题(只是烦了点
题面
在这里插入图片描述
数据范围不大,但暴力也不可能
在这里插入图片描述
一开始想了半天怎么加入题目中的压缩条件,候命想了很久想到可以先算不压缩的再推压缩的,结果没想到h[i]>k的情况的蛋糕也能压,然后就…再到后来检查修改的代码查了半天才发现因为数组至少要开到t*5/4才行,所以,我又开小越界了…所以最后总结一下,其实就是开个完全背包求不压的情况下每个高度最多的营养价值再压缩加上一块h[i]>k的蛋糕更新后求最值就行了。
(GYF专用代码粘上)

#include<bits/stdc++.h>
using namespace std;
#define s1(a,n) sort(a+1,a+n+1)
#define s2(a,n) sort(a+1,a+n+1,mc)
#define ll long long
#define sg string
#define st struct
#define f1(i,l,r) for(int i=l;i<=r;++i)
#define f2(i,r,l) for(int i=r;i>=l;--i)
#define f3(i,a,b) for(int i=a;i;i=b)
#define me(a,b) memset(a,b,sizeof(a))
#define sf scanf
#define pf printf
#define fi(a) freopen(a,"r",stdin)
#define fo(a) freopen(a,"w",stdout)
#define cn continue
#define bk break
#define rt return
#define ct const
ct int maxn=1250+10;
int n,t,k,maxx,f[maxn]={},v[maxn],h[maxn];
bool mc(int x,int y){
	rt x>y;
}
void init(){
	sf("%d%d%d",&n,&t,&k);
	f1(i,1,n) sf("%d%d",&v[i],&h[i]);
}
void work(){
	f1(i,1,n) f1(j,h[i],t*5/4) f[j]=max(f[j],f[j-h[i]]+v[i]); 
	maxx=f[t];
	f1(i,1,n) if(h[i]>=k) maxx=max(maxx,f[(t-h[i])*5/4]+v[i]);
}
void prin(){
	pf("%d",maxx);
}
int main(){
	fi("cheese..in");
	fo("cheese..out");
	init();
	work();
	prin();
	rt 0;
}

第三题

一眼没思路,过样例,切题目,过会再来看(考试时…)
于是后面我就没时间看了
题面
在这里插入图片描述
(数据范围在题目中)
说白了,不就围成一个圈打架看有没有可能赢吗…
这题很明显的区间dp,用f[i][j][k]来表示i到j的区间中k有没有可能获胜,在这样推导到全部,但要注意因为围成了一个圈,要再复制一边放到原有数组的结尾来操作(就因为这个没考虑到数组爆了查了半天…
还有就是五重循环那要特别小心呐。
(GYF专用代码粘上)

#include<bits/stdc++.h>
using namespace std;
#define s1(a,n) sort(a+1,a+n+1)
#define s2(a,n) sort(a+1,a+n+1,mc)
#define ll long long
#define sg string
#define st struct
#define f1(i,l,r) for(int i=l;i<=r;++i)
#define f2(i,r,l) for(int i=r;i>=l;--i)
#define f3(i,a,b) for(int i=a;i;i=b)
#define me(a,b) memset(a,b,sizeof(a))
#define sf scanf
#define pf printf
#define fi(a) freopen(a,"r",stdin)
#define fo(a) freopen(a,"w",stdout)
#define cn continue
#define bk break
#define rt return
#define ct const
ct int maxn=40+10;
int n,a[maxn*2][maxn*2],f[maxn*2][maxn*2][maxn*2],k,q; 
bool mc(int x,int y){
	return x>y;
}
void init(){
	sf("%d",&n);
	f1(i,1,n){
		f1(j,1,n){
			sf("%d",&a[i][j]);
			a[i+n][j]=a[i][j+n]=a[i+n][j+n]=a[i][j];
		}
	}
	f1(i,1,n*2) f[i][i][i]=1;
}
void work(){
	f1(l,2,n){
		f1(i,1,n*2-l+1){
			k=i+l-1;
			f1(j,i,k){
				f1(l,i,j-1){
					f1(r,j,k){
						if(f[i][j-1][l]&&f[j][k][r]){
							if(a[l][r]) f[i][k][l]=1;
							else f[i][j][r]=1;
						}
					}
				}
			}
		}
	}
}
void prin(){
	f1(i,1,n){
		q=1;
		f1(j,1,n){
			if(f[j][j+n-1][i]){
				q=0;
				pf("1\n");
				bk;
			}
		}
		if(q) pf("0\n");
	} 
}
int main(){
	fi("data.in");
	fo("data.out");
	init();
	work();
	prin();
	rt 0;
}

第四题

本次最难…
题面
在这里插入图片描述
数据范围
在这里插入图片描述
完全没思路
那就说一下吧(虽然我还是没很搞懂)。
首先我们不难发现,对于两个区间 [l1,r1][l2,r2] ,如果满足l1,r1,l2,r2满足l2<=r1或者l1<=r2,则这两个区间可以合并为一个区间。若当前位置i不被任何区间包括,我们可以新建一个区间[i,i]。我们还要统计一下每一个区间的’a’—‘z’的个数,方便我们下面的操作。
你可以爆搜加记忆化,不过原理和下面的dp 是一样的,或者说根本没什么区别。
所以我们可以开始愉快的dp了,设f[i][j]表示以S 串的第i个区间为开头,T串的第j个字符为开头的最长公共子串的最大长度(至于转移的话随便搞搞就好了 )。对于j~j+g[i]-1(g[i]是第i 个区间的长度)的比较,直接一个个枚举就好了,这里就要用到我们刚刚统计的区间‘a’— ‘z’的个数了。假设当前搜到k 这个位置,t[k]在T[j…k]中出现的次数已经超过了S的i区间中t[k]的个数的话,那j到k-1的长度就是这个区间与j 开头的最长公共子串的最大长度。如果 j~j+g[i]-1 都是可以的,这个长度就变成了g[i]+f[i+1][j+g[i]]。dp 做完后对于每个i,j 可能还有S的i区间的开头[x-i区间的开头-1]=t[j-x,j-1] ,对于这部分我们可以再枚举一次,比较每一个的答案取最大值。
比较繁琐吧…
看代码试试?
(GYF专用代码粘上)

#include<bits/stdc++.h>
using namespace std;
#define s1(a,n) sort(a+1,a+n+1)
#define s2(a,n) sort(a+1,a+n+1,mc)
#define ll long long
#define sg string
#define st struct
#define f1(i,l,r) for(int i=l;i<=r;++i)
#define f2(i,r,l) for(int i=r;i>=l;--i)
#define f3(i,a,b) for(int i=a;i;i=b)
#define me(a,b) memset(a,b,sizeof(a))
#define sf scanf
#define pf printf
#define fi(a) freopen(a,"r",stdin)
#define fo(a) freopen(a,"w",stdout)
#define cn continue
#define bk break
#define rt return
#define ct const
ct int maxn=2000+10;
st lcs{
	int l,r;
}e[100010],z[maxn];
char t[maxn],s[maxn];
int p,k,n,m,R,L,tot=0,ans=0,sum,tt['z'+10][maxn],ss['z'+10][maxn],g[maxn],f[maxn][maxn];
bool mc(lcs x,lcs y){
	rt x.l<y.l||(x.l==y.l&&x.r<y.r);
}
void init(){
	sf("%s",t+1);
	m=strlen(t+1);
	sf("%s",s+1);
	n=strlen(s+1);
	sf("%d",&k);
	f1(i,1,k){
		sf("%d%d",&e[i].l,&e[i].r);
		++e[i].l;
		++e[i].r;
	}
	f1(i,1,n){
		++k;
		e[k].l=e[k].r=i;
	}
	s2(e,k);
	e[k+1].l=99999999;
	L=e[1].l;
	R=e[1].r;
	f1(i,2,k+1){
		if(R>=e[i].l) R=max(R,e[i].r);
		else{
			++tot;
			z[tot].l=L;
			z[tot].r=R;
			g[tot]=R-L+1;
			L=e[i].l;
			R=e[i].r;
		}
	}
	f1(i,1,m){
		f1(j,'a','z') tt[j][i]=tt[j][i-1];
		++tt[t[i]][i];
	}
	f1(i,1,tot) f1(j,z[i].l,z[i].r) ++ss[s[j]][i];
}
void work(){
	f2(i,tot,1){
		f2(j,m,1){
			p=0;
			f1(h,j,min(m,j+g[i]-1)){
				if(tt[t[h]][h]-tt[t[h]][j-1]>ss[t[h]][i]){
					p=1;
					bk;
				}
				else ++f[i][j];
			}
			if(!p) f[i][j]+=f[i+1][j+g[i]];
			sum=0;
			f2(h,j-1,max(1,j-g[i-1])){
				if(tt[t[h]][j-1]-tt[t[h]][h-1]>ss[t[h]][i-1]) bk;
				else ++sum;
			}
			ans=max(ans,f[i][j]+sum);
		}
	}
}
void prin(){
	pf("%d",ans);
}
int main(){
	fi("lcs.in");
	fo("lcs.out");
	init();
	work();
	prin();
	rt 0;
}

好长啊…

第五题

终于最后一题了…
题面
在这里插入图片描述
数据范围
在这里插入图片描述
其实这题我是觉得不难的,只要建树建好就行了(甚至可以不建),但是,我没看清题目,为什么约数和要小于这个数啊…
所以其实只要你以‘1’为根建一棵边权为1的树求直径即可,想一想是不是?
而且你实在不行不是还有一个4的点可以送你10分吗,或者你还可以打表啊
(GYF专用代码粘上)

#include<bits/stdc++.h>
using namespace std;
#define s1(a,n) sort(a+1,a+n+1)
#define s2(a,n) sort(a+1,a+n+1,mc)
#define ll long long
#define sg string
#define st struct
#define f1(i,l,r) for(int i=l;i<=r;++i)
#define f2(i,r,l) for(int i=r;i>=l;--i)
#define f3(i,a,b) for(int i=a;i;i=b)
#define me(a,b) memset(a,b,sizeof(a))
#define sf scanf
#define pf printf
#define fi(a) freopen(a,"r",stdin)
#define fo(a) freopen(a,"w",stdout)
#define cn continue
#define bk break
#define rt return
#define ct const
ct int maxn=50000+10;
st tra{
	int x,y,z;
}e[maxn*2];
int n,f[maxn],ans=0,Top[maxn],d1[maxn],d2[maxn];
bool mc(int x,int y){
	rt x>y;
}
void Add(int xx,int yy){
	++ans;
	e[ans].y=yy;
	e[ans].z=1;
	e[ans].x=Top[xx];
	Top[xx]=ans;
}
void init(){
	sf("%d",&n);
	f1(i,2,n){
		f[i]=1;
		f1(j,2,sqrt(i)){
			if(j*j==i) f[i]+=j;
			else if(i%j==0) f[i]+=j+i/j;
		}
	}
	f1(i,2,n){
		if(f[i]<i){
			Add(i,f[i]);
			Add(f[i],i);
		}
	}
}
void gg(int k,int fa){
	f3(i,Top[k],e[i].x){
		if(e[i].y==fa) cn;
		gg(e[i].y,k);
		if(d1[k]<d1[e[i].y]+e[i].z){
			d2[k]=d1[k];
			d1[k]=d1[e[i].y]+e[i].z;
		}
		else if(d2[k]<d1[e[i].y]+e[i].z) d2[k]=d1[e[i].y]+e[i].z;
	}
}
void work(){
	gg(1,0);
}
void prin(){
	pf("%d",d1[1]+d2[1]);
}
int main(){
	fi("transfer.in");
	fo("transfer.out");
	init();
	work();
	prin();
	rt 0;
}

Over,感谢各位奆佬捧场,GYF感激不尽(orz)。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值