加载中…

返回上一页

2022NOIP A层联测26

下发文件(密码为原 accoders 比赛密码)

乘筛积

按照题意模拟就可以得到 50 分.

点击查看代码
#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define ll long long
#define ld long double
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 300001
#define mod 998244353
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
ll n,m,c,t,p,q,ans,a[maxn],b[maxn];
int main()
{
	freopen("sedge.in","r",stdin); freopen("sedge.out","w",stdout);
	// freopen("in.txt","r",stdin); freopen("out.txt","w",stdout);
	n=read();m=read();c=read(); for(rll i=1;i<=n;i++) a[i]=read(); for(rll i=1;i<=m;i++) b[i]=read();
	t=read(); while(t--)
	{
		ans=0;p=read();q=read();
		for(rll j=max((ll)__builtin_ceill((ld)(c-p*n))/q,1ll),i;j<=m&&j*q<c;j++)
			{ i=c-j*q; if(!(i%p)) i/=p,(ans+=a[i]*b[j]%mod)%=mod/*,write(i),put_,write(j),putn*/; }
		write(ans);putn;
	}
	return 0;
}

评测结果:

Time Limit Exceeded 50

找到第一个出现的位置,每次将 y 位置加上 gcd(p , q),x 位置减去 gcd(p , q).

记忆化一下,将以前获得过的答案存起来.

能够通过子任务 6、7,获得 70 分.

点击查看代码
#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define ll int
#define ld long double
#define rg register
#define rll rg ll
#define ull unsigned long long
#define pll pair<ll,ll>
#define maxn 300001
#define mod 998244353
#define bs 125043281
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
ll n,m,c,t,p,q,ans,a[maxn],b[maxn];
unordered_map<ull,ll> mp;
ull pp;
inline ll gcd(rll x,rll y) { if(!y) return x; return gcd(y,x%y); }
int main()
{
	freopen("sedge.in","r",stdin); freopen("sedge.out","w",stdout);
	// freopen("in.txt","r",stdin); freopen("out.txt","w",stdout);
	n=read();m=read();c=read(); for(rll i=1;i<=n;i++) a[i]=read(); for(rll i=1;i<=m;i++) b[i]=read();
	t=read(); while(t--)
	{
		ans=0;p=read();q=read(); pp=(ull)p*bs+q; if(mp.find(pp)!=mp.end()) { write(mp[pp]),putn;continue; }
		rll x=0,y=0,g=gcd(p,q); if(c%g) { puts("0");continue; }
		for(rll j=1,i;j<=m&&j*q<c;j++)
			{ i=c-j*q; if(!(i%p)) { i/=p;x=i,y=j; break; } }
		// cout<<x<<' '<<y<<endl;
		while(x>=1&&y<=m) (ans+=(long long)a[x]*b[y]%mod)%=mod,x-=q/g,y+=p/g;// ,cout<<x<<' '<<y<<endl;
		write(mp[pp]=ans);putn;
	}
	return 0;
}

评测结果:

Time Limit Exceeded 70

优化一下,如果 p 较大就枚举 x,反之则枚举 y. 能够通过子任务 8、9、10,得到 100 分.

点击查看代码
#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define ll int
#define ld long double
#define rg register
#define rll rg ll
#define ull unsigned long long
#define pll pair<ll,ll>
#define maxn 300001
#define mod 998244353
#define bs 125043281
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
ll n,m,c,t,p,q,ans,a[maxn],b[maxn];
unordered_map<ull,ll> mp;
inline ll gcd(rll x,rll y) { if(!y) return x; return gcd(y,x%y); }
int main()
{
	freopen("sedge.in","r",stdin); freopen("sedge.out","w",stdout);
	// freopen("in.txt","r",stdin); freopen("out.txt","w",stdout);
	n=read();m=read();c=read(); for(rll i=1;i<=n;i++) a[i]=read(); for(rll i=1;i<=m;i++) b[i]=read();
	t=read(); while(t--)
	{
		ans=0;p=read();q=read(); if(mp[(ull)p*bs+q]) { write(mp[(ull)p*bs+q]),putn;continue; }
		rll x=0,y=0,g=gcd(p,q); if(c%g) { puts("0");continue; }
		if(p>q) for(rll i=1,j;i<=n&&i*p<c;i++)
			{ j=c-i*p; if(!(j%q)) { j/=q;x=i,y=j; break; } }
		else for(rll j=1,i;j<=m&&j*q<c;j++)
			{ i=c-j*q; if(!(i%p)) { i/=p;x=i,y=j; break; } }
		// cout<<x<<' '<<y<<endl;
		if(p>q) while(x<=n&&y>=1) (ans+=(long long)a[x]*b[y]%mod)%=mod,x+=q/g,y-=p/g;// ,cout<<x<<' '<<y<<endl;
		else while(x>=1&&y<=m) (ans+=(long long)a[x]*b[y]%mod)%=mod,x-=q/g,y+=p/g;// ,cout<<x<<' '<<y<<endl;
		mp[(ull)p*bs+q]=ans; write(ans);putn;
	}
	return 0;
}

评测结果:

Accepted 100

放进去

我写的做法是贪心,据说是假了,但是我认为正确性应该没什么问题,而且不知道为什么我的做法也没被 hack 数据卡掉.

前置唠叨:

一定要注意对每个机器人按照 b 值排序!一定要排序!贪心是要满足单调性的!因为这个考场上 100 分变爆零了!

既然是贪心,那么肯定是选择一种最优的方案. 因此就是上面说的,一定要对每个机器人按照 b 排序,优先选择代价最小的.

先把所有购买的都扣在第一个机器人上. 然后遍历第 2 ~ n 个机器人,分两种情况:

  1. 出现价格便宜的时候,记录一下价格的差值

  2. 在去除掉第一种情况的所有已更改物品之后,记录一下前面每个机器人的剩余物品和 b之和,如果它比新的当前机器人的总和要大,就删除前面的那个,记录一下差值.

如果总的差值比当前的 b 小,那么就不选当前机器人. 否则就选.

还有一点其实不需要,因为已经保证了单调性了. 就是每次选完后找到当前已选的机器人中每个物品的最小价格,更新一下. 这个是我原来调试用的,其实并不需要.

点击查看代码
#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 100001
#define maxm 26
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
ll n,m,ans=0x3f3f3f3f3f3f3f3f,a[maxn][maxm],b[maxm],mn[maxn],cnt[maxm],sum[maxm],tot[maxm],id[maxn],num[maxn];
inline bool cmp(rll x,rll y){ return b[x]<b[y]; }
int main()
{
	freopen("putin.in","r",stdin); freopen("putin.out","w",stdout);
	// freopen("in.txt","r",stdin);// freopen("out.txt","w",stdout);
	n=read();m=read(); for(rll i=1;i<=n;i++) for(rll j=1;j<=m;j++) a[i][j]=read();
	for(rll i=1;i<=m;i++) b[i]=read(),num[i]=i;
	sort(num+1,num+m+1,cmp);
	// for(rll p=1;p<=m;p++)
	{
		// memset(cnt,0,sizeof(cnt));
		cnt[num[1]]=n; for(rll i=1;i<=n;i++) mn[i]=a[i][num[1]],id[i]=num[1];
		for(rll j=2;j<=m;j++)
		{
			rll cz=0; memset(tot,0,sizeof(tot)); memset(sum,0,sizeof(sum));
			for(rll i=1;i<=n;i++) if(mn[i]>=a[i][num[j]]) cz+=mn[i]-a[i][num[j]],tot[id[i]]++; else sum[id[i]]+=mn[i]-a[i][num[j]];
			// for(rll i=1;i<=m;i++) if((i^num[j])&&cnt[i]&&(tot[i]==cnt[i]||sum[i]+b[i]>0)) assert(sum[i]+b[i]>=0),cz+=sum[i]+b[i];// ,printf("cz = %lld\n",cz);
			if(cz-b[num[j]]>0) for(rll i=1;i<=n;i++) if(mn[i]>=a[i][num[j]]||sum[id[i]]+b[id[i]]>0)
				mn[i]=a[i][num[j]],cnt[id[i]]--,cnt[id[i]=num[j]]++;
			for(rll i=1;i<=n;i++) for(rll k=1;k<=m;k++) if(cnt[k]&&mn[i]>=a[i][k]) mn[i]=a[i][k],cnt[id[i]]--,cnt[id[i]=k]++;
			// cout<<cz<<' '<<b[j]<<endl;
			// for(rll i=1;i<=n;i++) write(mn[i]),put_;putn;for(rll i=1;i<=n;i++) write(id[i]),put_;putn;for(rll i=1;i<=m;i++) if(cnt[i]) write(i),put_;putn;
		}
		rll t=0; for(rll i=1;i<=n;i++) t+=mn[i]; for(rll j=1;j<=m;j++) if(cnt[j]) assert(cnt[j]>0),t+=b[j]; ans=min(ans,t); // 这儿没必要,因为前面的 sort 已经保证单调性了.
	}
	write(ans);
	return 0;
}

评测结果:

Accepted 100

正解实际上是个子集和 dp.

推荐看一下这道题,和本题非常类似. 就是初始花费变为了全部是 t.

最长路径

生成树的传说

后面两个题没有改.

posted @ 2022-11-12 19:12  1Liu  阅读(11)  评论(1编辑  收藏  举报