其他分享
首页 > 其他分享> > NOIP模拟11

NOIP模拟11

作者:互联网

期望得分: 20 + 40 + 40 = 100

实际得分: 20 + 0 + 30 =50

本来打算打完 T2 T3 暴力再回来想 T1 正解,可由于码力弱写假,导致 T2 T3 的大样例迟迟不能输出正解,最后惨淡结束比赛
其实 T1 我想偏了,当时想到了 ax+by=z 条件是 gcd(a,b)|z 但由于把知识学死了,导致错过正解
于是我将 T1 完全当作成一个凑数题,推导出每个 \(a_i*b_i mod k\) 可以产生的数为\([0 , \frac{k}{gcd(a_i,k)}-1]*gcd(a_i,k)\)
在此时我仍然有一个可以拿到 50pts 的机会,那就是跑背包来记录[0,k) 内数是否可以被凑出,使用滚动数组防止爆空间,时间复杂度\(O(n k \frac{k}{gcd(a_i,k)})\),我仍然没有想到背包,只是草草打上 dfs 就走开了

对于 T2,考试时思路是,先按照 a排序,同样的\(a_{i,j}\)分在同组,然后dp,定义 f[i][j]为 前i组跳蚤数目中,第i组中选第j个的最大值,由于 b 为正数,且坐标加了绝对值,也就是说,使经过的 a 的组数尽可能多
那么,\(f[i][j]=max(f[i-1][k]+b[i][j]+ |x[i][j]-x[i-1][k]|+|y[i][j]-y[i-1][k]|)\)
这样的话,由于组数未知,可以对f[i]开个vector,时间复杂度 \(O(nm*num^2)\)
但是,我没关 freopen,并且 在f 的 vector 与矩阵的普通数组对应中忘记将下标+1,导致 0pts
正解就是将曼哈顿距离转化为切比雪夫距离,将坐标 \((i,j)\)转化为\((i+j,i-j)\),同时将\(max(|i-i'|+|j-j'|)\),转化为\(max(|i-i'|,|j-j'|)\),这样的话,针对\(i-i'\) , \(i'-i\) , \(j-j'\) , \(j'-j\) , 四种情况可以分别记录四个变量来更新,时间复杂度\(O(nm)\)

T3,我枚举区间,用倍增查找区间最大值,时间复杂度\(O(n^2logn)\)
而特殊的, a_i 只有 0/1 ,若 opt=1,两端都为1或0,贡献为0;两端分别 01,贡献为1。所以只用分别求个01前缀和就行了,时间复杂度\(O(n)\)
若opt=2,无论怎样都无法满足异或后值大于区间max,直接输出0
由于我只维护0,没有维护1,导致由 40 pts 降为 30 pts

T1 math

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=500011;
int n,k,a[N];
int ans;
int gd[N];
bool jud[N*2];
inline int read()
{
	int s=0;
	char ch=getchar();
	while(ch>'9'||ch<'0')
		ch=getchar();
	while(ch>='0'&&ch<='9')
	{
		s=(s<<1)+(s<<3)+(ch^48);
		ch=getchar();
	}
	return s;
}
int gcd(int x,int y)
{
	if(!y)
		return x;
	return gcd(y,x%y);
}
signed main()
{
	n=read();
	k=read();
	gd[0]=a[1]=read();
	for(int i=2;i<=n;i++)
	{
		a[i]=read();
		if(gd[0]&&a[i])
			gd[0]=gcd(a[i],gd[0]);
	}
	gd[0]=gcd(gd[0],k);
	for(int i=0;i<k;i++)
		if(!(i%gd[0]))
		{
			ans++;
			jud[i]=1;
		}
	printf("%lld\n",ans);
	for(int i=0;i<k;i++)
		if(jud[i])
			printf("%lld ",i);
	return 0;
}

T2

#include<bits/stdc++.h>
using namespace std;
const int N=1000011;
struct mat_{
	long long a,b;
	long long x,y;
}mat[N*4];
long long a1,a2,b1,b2;
long long a11,a22,b11,b22;
long long sum,ans;
int n,m;
int kd;
int sl;
inline int read()
{
	int s=0;
	char ch=getchar();
	while(ch>'9'||ch<'0')
		ch=getchar();
	while(ch>='0'&&ch<='9')
	{
		s=(s<<1)+(s<<3)+(ch^48);
		ch=getchar();
	}
	return s;
}
bool cmp(mat_ a,mat_ b)
{
	if(a.a!=b.a)
		return a.a<b.a;
	if(a.b!=b.b)
		return a.b<b.b;
	return 0;
}
signed main()
{
//	freopen("c.in","r",stdin);
//	freopen("zj1.out","w",stdout);
	int l,r;
	n=read();
	m=read();
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			mat[++sl].a=read();
			mat[sl].x=i+j;
			mat[sl].y=i-j;
		}
	sl=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			mat[++sl].b=read();
	sort(mat+1,mat+sl+1,cmp);
	for(int i=1;i<=sl;i++)
		if(mat[i].a)
		{
			l=i;
			break;
		}
	a11=mat[l].b+mat[l].x;
	a22=mat[l].b-mat[l].x;
	b11=mat[l].b+mat[l].y;
	b22=mat[l].b-mat[l].y;
	for(int i=l+1;i<=sl;i++)
	{
		if(mat[i].a>mat[i-1].a)
		{
			l=i;
			break;
		}
		a11=max(a11,mat[i].b+mat[i].x);
		a22=max(a22,mat[i].b-mat[i].x);
		b11=max(b11,mat[i].b+mat[i].y);
		b22=max(b22,mat[i].b-mat[i].y);
	}
	for(int i=l;i<=sl;i++)
	{
		if(mat[i].a>mat[i-1].a)
		{
			a1=a11;
			a2=a22;
			b1=b11;
			b2=b22;
			a11=a22=b11=b22=0;
		}
		sum=(max(max(a1-mat[i].x,a2+mat[i].x),max(b1-mat[i].y,b2+mat[i].y))+mat[i].b);
		a11=max(a11,sum+mat[i].x);
		a22=max(a22,sum-mat[i].x);
		b11=max(b11,sum+mat[i].y);
		b22=max(b22,sum-mat[i].y);
		ans=max(sum,ans);
	}
	cout<<ans;
	return 0;
}

T3的题解没有看懂

这篇博客里 “但是” 这个词出现了很多次,现在我只想说,虽然我现在很弱,但当我将所想都可以实现时,仍能拿到可观的分数。避免代码的失误,先将思路捋清,将每一步预先想好,再写代码
再一次回顾考试时的心态变化,和写代码习惯,我的精力和思考并没有全部发挥,只是大部分时间去调试程序,而没有保持思考可能存在的问题,或用来推导正解
知识的不足仍然也是重要问题,刷题少,知识学得死,在学知识时要多去想证明和应用,还有相似的扩展

标签:11,a11,mat,NOIP,int,max,b22,long,模拟
来源: https://www.cnblogs.com/sitiy/p/14999572.html