2019.01.26【NOIP提高组】模拟 B 组 比赛总结

总结

这次比赛比昨天可做了一些。
T1:
死磕了2h,毫无头绪,感觉像是贪心,又像是二分。最后只好打暴力了。
T2:
一眼出正解,此乃背包!设 f i , j f_{i,j} fi,j表示第 j 天在城市 i 的最少花费。然后就一通乱搞……
但坑×的是,郭嘉居然不能在城市里连续呆几天!
T3:
感觉不可做。应该是DP吧!

OJ bug报告:

11:17:26

什么鬼?我半个小时前交的代码居然……
在这里插入图片描述

11:18:46

在这里插入图片描述
啊,OJ爆了!

11:19:21

在这里插入图片描述
好吧,OJ真的爆了。我只好默默地拿出作业……

11:20:46

在这里插入图片描述
还没运行完啊!
这时,XC怒不可歇地冲了进来说:“(代码)没运行完的不要重复交啊,我看有的人都交了好几遍了。你们这不是给OJ添堵吗?”
N个人愧怍地低下了头。

After the contest

于是乎,成绩刚出的时候
在这里插入图片描述
我居然没有爆〇耶!一定是昨晚做值日攒足了人品(吃宵夜被抓T_T,结果被XC安排去扫3、4楼所有教室,别的还好,在肮脏的403扫了足足7袋垃圾!)。
这个故事告诉我们:要多做值日,实在不行可以在表上多登几个名字。做值日不要紧,人品才是最重要的<(▰˘◡˘▰)
睡醒午觉后,就多了100分了。
在这里插入图片描述


题解

T1

解法1(水法)

这题我打暴力拿了50分~按理说我接下来会废掉暴力重新打正解的,可是我发现那50的暴力并没有TLE耶!
在这里插入图片描述
于是我就开始查错误……提交……AC!
虽然暴力理论上的时间复杂度是 ,但是加上一堆猥琐剪枝后它完全可以变成这样:
在这里插入图片描述
Amazing!

解法2

大佬们用了折半搜索
先是枚举前半段,答案放入数组a中,再是枚举后半段,答案放入数组b中。这时我们就得到了两个长度为2^(n/2)的数组,只要想办法把它们组合起来,使结果合法并最大化就可以了。
于是自然而然地就想到了二分。可以先把数组a排序,再在数组b中枚举每一个数,在a数组中二分查找满足 的最大a值,更新答案即可。

解法3

LZY说不一定要二分查找。
可以把两个数组都排序,接着一个指针指着 ,另一个指着的 ,用类似于双指针搜索的方法查找就可以了。
当然,这个方法的常数似乎不太优秀……

T2

解法一

比赛时我一眼出正解,这题难道不是DP吗?
f i , j f_{i,j} fi,j表示第 j 天在城市 i 的最少花费。状态转移方程就为
f i , j = { f i , j − 1 在城市中多呆一天 f k , j − 1 + w k , i , j w k , i , j ≠ 0 f_{i,j}= \begin{cases} f_{i,j-1} & \text{在城市中多呆一天} \\ f_{k,j-1}+w_{k,i,j} & \text{$w_{k,i,j}\neq 0$} \end{cases} fi,j={ fi,j1fk,j1+wk,i,j在城市中多呆一天wk,i,j̸=0
w k , i , j w_{k,i,j} wk,i,j表示第 j 天从 k 到 i 的费用。
结果发现连样例都过不了。后来去掉了第一行的转移就AC了。
坑啊!为什么郭嘉大大不能在同一个城市住上几天呢?

解法二

这题也可以用最短路做,其实就是在原来最短路的基础上多开一维存时间。

T3

完全背包问题。
f i f_i fi表示美味值等于 i 时的最小体积, g i g_i gi表示运费为 i 时的最大体积。
乱搞一下就可以了。

感悟

1 ) RP很重要,平时生活中要多点积累RP。当然我们也要发扬乐于助人的精神,积极帮助他人攒人品,因此要多让别人请吃饭,也要促使他人搞卫生(不讲题目大意的时候千万不要提醒)
2 ) 我的基本功不是很扎实,一些基础的算法如搜索掌握程度不佳,要加强。
3 ) 雷灏讲题时一定要安静,最好忘记时间。
4 ) 总结写那么长会很耗时间的。雷灏是怎么做到的???

开源盛世

T1

#include<cstdio>
using namespace std;
#define ll long long
#define N 50
int a[N],n,m,ans;
ll f[N];
void dfs(int k,ll sum)
{
    
    
	if(sum>m) return;
	if(sum>ans) ans=sum;
	if(!k) return;
	if(sum+f[k]<=m)
	{
    
    
		if(sum+f[k]>ans) ans=sum+f[k];
		return;
	}
	dfs(k-1,sum);
	if(sum+a[k]<=m) dfs(k-1,sum+a[k]);
}
int main()
{
    
    
	int i,j;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++) scanf("%d",&a[i]),f[i]=f[i-1]+a[i];
	dfs(n,0);printf("%d\n",ans);
	return 0;
}

T2

#include<cstdio>
using namespace std;
#define inf 999999999
#define N 105
#define M 205
int f[N][M],a[N][N][25];
inline int min(int x,int y){
    
    return x<y?x:y;}
int main()
{
    
    
	freopen("lines.in","r",stdin);
	freopen("lines.out","w",stdout);
	int n,m,i,j,k,t;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)
	{
    
    
		for(j=1;j<=n;j++)
			if(j!=i)
			{
    
    
				scanf("%d",&a[i][j][0]);
				for(k=1;k<=a[i][j][0];k++)
					scanf("%d",&a[i][j][k]);
			}
		for(j=0;j<=m;j++) f[i][j]=inf;
	}
	f[1][0]=0;
	for(j=1;j<=m;j++)
	{
    
    
		for(i=1;i<=n;i++)
		{
    
    
			//f[i][j]=f[i][j-1];
			for(k=1;k<=n;k++) if(a[k][i][0])
			{
    
    
				t=a[k][i][j%a[k][i][0]?j%a[k][i][0]:a[k][i][0]];
				if(t)
					f[i][j]=min(f[i][j],f[k][j-1]+t);
			}
		}
	}
	if(f[n][m]!=inf) printf("%d\n",f[n][m]);
	else puts("0");
	return 0;
}

T3

#include<cstdio>
using namespace std;
#define inf 999999999
#define P 50105
#define N 5000
int n,m,p,num1,num2,f[P],g[P],t[N],u[N],x[N],y[N];
inline int max(int x,int y){
    
    return x>y?x:y;}
inline int min(int x,int y){
    
    return x<y?x:y;}
int main()
{
    
    
	int test,i,j,k,a,b,c,ans;
	scanf("%d",&test);
	while(test--)
	{
    
    
		scanf("%d%d%d",&n,&m,&p);
		num1=num2=0,ans=inf;
		for(i=1;i<=n;i++)
		{
    
    
			scanf("%d%d%d",&a,&b,&c);
			for(k=1;k<=c;k<<=1)
			{
    
    
				t[++num1]=a*k;
				u[num1]=b*k;
				c-=k;
			}
			if(c) t[++num1]=a*c,u[num1]=b*c;
		}
		for(i=1;i<=m;i++)
		{
    
    
			scanf("%d%d%d",&a,&b,&c);
			for(k=1;k<=c;k<<=1)
			{
    
    
				x[++num2]=a*k;
				y[num2]=b*k;
				c-=k;
			}
			if(c) x[++num2]=a*c,y[num2]=b*c;
		}
		for(i=1;i<P;i++) f[i]=inf,g[i]=-inf;
		for(i=1;i<=num1;i++)
			for(j=p+100;j>=0;j--)
				if(j>=t[i])
					f[j]=min(f[j],f[j-t[i]]+u[i]);
		for(j=p+99;j>=p;j--) f[j]=min(f[j+1],f[j]);
		ans=50000;
		for(i=1;i<=num2;i++)
			for(j=ans;j>=0;j--)
			{
    
    
				if(j>=y[i])
					g[j]=max(g[j],g[j-y[i]]+x[i]);
				if(g[j]>=f[p]) ans=min(ans,j);
			}
		if(ans<50000) printf("%d\n",ans);
		else puts("TAT");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huangzihaoal/article/details/86661831
今日推荐