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;
}
评测结果:
找到第一个出现的位置,每次将 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;
}
评测结果:
优化一下,如果 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 个机器人,分两种情况:
-
出现价格便宜的时候,记录一下价格的差值;
-
在去除掉第一种情况的所有已更改物品之后,记录一下前面每个机器人的剩余物品和 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.
最长路径
生成树的传说
后面两个题没有改.
--END--
我的博客: 𝟷𝙻𝚒𝚞
本文链接: https://www.cnblogs.com/1Liu/p/16884456.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!