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