11.20 NOIP2024模拟赛#25 div1

挂分力

T1

发现单点修更优,于是就成了拓欧板子

因为对于通解 \(x',y'\) 有通式:\(a(x+qb)+b(y-qa)=d\)

即求 \(\min\{|x+qb|+|y-qa|\}\)

然后考虑 \(q\) 在哪能取到最小

推出来了两个值,直接代,过掉了样例

然鹅这两个值有向上/下取整之分,所以需要代四个值

然后就 \(100 \rightarrow 80\)

赛后改一下就过了

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define ll long long
#define fd(i,a,b) for(int i=(a);i<=(b);i=-~i)
#define bd(i,a,b) for(int i=(a);i>=(b);i=~-i)
#define db(x) cout<<"DEBUG "<<#x<<" = "<<x<<endl;
#define endl '\n'
using namespace std;

//#define SIZE (1<<20)
//char In[SIZE],Out[SIZE],*p1=In,*p2=In,*p3=Out;
//#define getchar() (p1==p2&&(p2=(p1=In)+fread(In,1,SIZE,stdin),p1==p2)?EOF:*p1++)
template<typename _T=int>
inline _T read()
{
	_T x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c-48);c=getchar();}
	return x*f;
}

const int N=1e6+509,M=1e6+509,mod=998244353,inf=0x3f3f3f3f;

int n,a,b,v[N],ans;

pair<int,int> exgcd(int x,int y,int &d)
{
	if(!y) {d=x;return {1,0};}
	auto t=exgcd(y,x%y,d);
	return {t.second,t.first-x/y*t.second};
}

signed main()
{
#define FJ
#ifdef FJ
	freopen("tease.in","r",stdin);
	freopen("tease.out","w",stdout);
#else
//	freopen("ex_tease6.in","r",stdin);
//	freopen("tease.out","w",stdout);
#endif
//#define io
#ifdef io
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
#endif
	
	n=read(),a=read(),b=read();
	if(a<b) swap(a,b);
	fd(i,1,n) v[i]=abs(read());
	
	fd(i,1,n)
	{
		int c=v[i],x,y,d;
		auto s=exgcd(a,b,d);
		x=s.first,y=s.second;
		if(c%d!=0)
		{
			puts("-1");
			return 0;
		}
		int xx=x*c/d,yy=y*c/d,dx=b/d,dy=a/d;
		int s1=ceil(double(-xx+1)/double(dx)),s2=floor(double(yy-1)/double(dy)),s3=floor(double(-xx+1)/double(dx)),s4=ceil(double(yy-1)/double(dy));
		ans+=min({abs(s1*dx+xx)+abs(yy-s1*dy),abs(s2*dx+xx)+abs(yy-s2*dy),abs(s3*dx+xx)+abs(yy-s3*dy),abs(s4*dx+xx)+abs(yy-s4*dy),(c%a==0)?c/a:inf,(c%b==0)?c/b:inf});
	}
	
	printf("%lld\n",ans);
	
	return 0;
}

T2

一看 \(n=2\),这不是小凯的疑惑?

然后码了个 \(n=1\)\(n=2\),\(m \le 5\times 10^3\)

然后尝试测一下大样例

发现最小值一般很小,然后猜到答案不会很大

于是假设 \(m\) 的上限是 \(a_1\times a_2 - a_1 -a_2\)

然后多拿了 \(24\)

赛后发现这并不是上限,我假设的上限小了,开大一点可以再多拿 \(8\)

然后 \(n=2\) 时没有判 \((a_1,a_2)\) 不为 \(1\) 的情况,丢 \(4\)

这样算下来,其实可以有 \(72\) 分的

正解是同余最短路,因为 \(a_1\) 很小,所以复杂度是“能过”

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define ll long long
#define fd(i,a,b) for(int i=(a);i<=(b);i=-~i)
#define bd(i,a,b) for(int i=(a);i>=(b);i=~-i)
#define db(x) cout<<"DEBUG "<<#x<<" = "<<x<<endl;
#define endl '\n'
using namespace std;

//#define SIZE (1<<20)
//char In[SIZE],Out[SIZE],*p1=In,*p2=In,*p3=Out;
//#define getchar() (p1==p2&&(p2=(p1=In)+fread(In,1,SIZE,stdin),p1==p2)?EOF:*p1++)
template<typename _T=int>
inline _T read()
{
	_T x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c-48);c=getchar();}
	return x*f;
}

const int N=1e6+509,M=1e6+509,mod=998244353;

uint64_t PRG_state;
uint64_t get_number()
{
	PRG_state^=PRG_state<<13;
	PRG_state^=PRG_state>>7;
	PRG_state^=PRG_state<<17;
	return PRG_state;
}
int readW(int l,int r)
{
	return get_number()%(r-l+1)+l;
}

int n,lim,m;
int a[N];

inline void init()
{
	n=read(),lim=read(),m=read(),PRG_state=read<uint64_t>();
	fd(i,1,n) a[i]=readW(2,lim);
}

namespace SubI
{
	void Main()
	{
		if(n==1)
		{
			if(m%a[1]) printf("%lld",m);
			else printf("%lld",m-1);
			exit(0);
		}
		if(n==2)
		{
			int g=__gcd(a[1],a[2]);
			if(g==1) printf("%lld",a[1]*a[2]-a[1]-a[2]);
			else printf("%lld",(ll)1e18-(m%g==0));
			exit(0);
		}
	}
}

namespace SubII
{
	int d[M],mn,len,e[N],ans,num[N];
	bool vis[M];
	void dij()
	{
		memset(d,10,sizeof(d));
		memset(vis,0,sizeof(vis));
		d[0]=0;
		priority_queue< pair<int,int> > q;
		q.push({0,0});
		while(!q.empty())
		{
			int x=q.top().second;q.pop();
            if(vis[x]) continue;
            vis[x]=1;
            fd(i,1,len)
            {
				int y=(x+e[i])%mn;
                if(d[y]<=d[x]+e[i]) continue;
                d[y]=d[x]+e[i];
                q.push({-d[y],y});
            }
		}
	}
	inline void Main()
	{
		mn=a[1];
		memset(num,10,sizeof(num));
		fd(i,1,n) if(a[i]%mn) num[a[i]%mn]=min(num[a[i]%mn],a[i]);
		fd(i,1,mn-1) if(num[i]<=1e8) e[++len]=num[i];
		dij();
		fd(i,1,mn-1)
		{
			if(d[i]<=m) ans=max(ans,d[i]-mn);
			else
			{
				int k=(d[i]-m-1)/mn+1;
				ans=max(ans,d[i]-k*mn);
			}
		}
		printf("%lld",ans);
	}
}

signed main()
{
#define FJ
#ifdef FJ
	freopen("doubt.in","r",stdin);
	freopen("doubt.out","w",stdout);
#else
//	freopen("doubt1.in","r",stdin);
//	freopen("doubt.out","w",stdout);
#endif
//#define io
#ifdef io
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
#endif
	
	init();

	sort(a+1,a+n+1);
	n=unique(a+1,a+n+1)-a-1;

	if(n<=2) SubI::Main();
	else SubII::Main();
	
	return 0;
}

T3

题都没看懂……

正解是注意到状态数很少

然后跑容斥 DP 即可

看 T4 了

T4

一眼 Trie,然后可以莫队维护

但是我忘了怎么删数,然后就码的离线+Trie

然后拿到 \(40\)

正解是莫二离……

总结

  • T1 挂
  • T2 挂
  • 莫队需要巩固一下
  • “注意到”
posted @ 2024-11-22 19:21  whrwlx  阅读(2)  评论(0编辑  收藏  举报