4 条题解
-
3
解题过程(时间复杂度优化)
暴力
数据范围N<=1e5,Q<=1e5,暴力复杂度最差为,就是对于每一个询问都从a到b跑一边,看需要多少天。
暴力后就可以根据分数进行下一步优化(但XCPC赛制并不允许查看分数,所以这是个事后诸葛亮......)
#include<bits/stdc++.h> using namespace std; #define ll long long ll n,a[100010],q,l,s[100010]; ll solve(ll x,ll y) { ll day=0,t=0; for(ll i=x+1;i<=y;i++) { t+=a[i]-a[i-1]; if(t>l)day++,t=0,i--; } if(t>0)day++; return day; } int main() { scanf("%lld",&n); for(ll i=1;i<=n;i++)scanf("%lld",&a[i]); scanf("%lld%lld",&l,&q); while(q--) { ll x,y;scanf("%lld%lld",&x,&y); if(x>y)swap(x,y); printf("%lld\n",solve(x,y)); } return 0; }优化
然后我们就会得到这个76分的代码,注意到分数超过3/4,所以复杂度再优化半层即可......
暴力时间复杂度为,其中Q是输入输出必须跑的一环,故无法改变,所以我们只能在N上做文章
N往下自然就是logN了,那我们要如何实现呢???
方法
再次分析题目,题目要求我们是每天尽量多赶路,但不能超过距离限制且要到达一个有酒店的点。
这时这一条坐标轴是不是就成了一条链,我们要在相同时间内尽量走得更远?
那就可以使用st表来暴力维护每个点向右走天最远能到哪个酒店,然后就暴力跳。(虽然题目没有保证a<b,但我们swap一下就可以了)
这样一来,就十分自然地降成了,然后就能AC了...
#include<bits/stdc++.h> using namespace std; const int N=2e5+10; int a[N],st[N][21],n,L,q,x,y; int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); scanf("%d%d",&L,&q); for(int l=1,r=1;l<=n;l++) { while(r<n&&a[r+1]-a[l]<=L)r++; st[l][0]=r; } for(int i=1;i<=20;i++)for(int j=1;j<=n;j++)st[j][i]=st[st[j][i-1]][i-1]; while(q--) { scanf("%d%d",&x,&y);int ans=0; if(x>y)swap(x,y); for(int i=20;i>=0;i--)if(st[x][i]<y)x=st[x][i],ans+=(1<<i); printf("%d\n",ans+1); } return 0; }tip
比赛时用了一个前缀和的思路来算,从酒店1开始处理,且中途没有改变起点,那自然是WA的,只有18分......
#include<bits/stdc++.h> using namespace std; #define ll long long ll n,a[100010],q,l,s[100010],k[100010]; int main() { scanf("%lld",&n); for(ll i=1;i<=n;i++)scanf("%lld",&a[i]); scanf("%lld%lld",&l,&q); s[1]=0;k[1]=0; for(ll i=2;i<=n;i++) { k[i]=k[i-1]+a[i]-a[i-1];s[i]=s[i-1]; //printf("%lld %lld\n",k[i],s[i]); if(k[i]==l)s[i]++,k[i]=0; else if(k[i]>l)s[i-1]++,i--,k[i]=0; //printf("%lld %lld\n\n",k[i],s[i]); } //for(ll i=1;i<=n;i++)printf("%lld\n",s[i]); while(q--) { ll x,y;scanf("%lld%lld",&x,&y); if(x>y)swap(x,y); if(s[y]==s[x])puts("1"); else printf("%lld\n",s[y]-s[x]); } return 0; } -
3
十分钟切掉的送分题,这题我以前好像做过。
其实没啥好讲的。只需要注意到从左到右和从右到左其实没什么区别。
直接 st 表暴力维护每个点往右 天最远能到哪个酒店,然后就暴力跳。时间复杂度 。
#include<bits/stdc++.h> using namespace std; const int N=2e5+10; int a[N],st[N][21]; signed main() { int n,L;cin>>n; for(int i=1;i<=n;i++)cin>>a[i]; cin>>L; for(int l=1,r=1;l<=n;l++) { while(r<n&&a[r+1]-a[l]<=L)r++; st[l][0]=r; } for(int i=1;i<=20;i++)for(int j=1;j<=n;j++)st[j][i]=st[st[j][i-1]][i-1]; int q;cin>>q; while(q--) { int x,y;cin>>x>>y;int ans=0;if(x>y)swap(x,y); for(int i=20;i>=0;i--)if(st[x][i]<y)x=st[x][i],ans+=(1<<i); cout<<ans+1<<'\n'; } return 0; } -
0
一天一天地跳显然超时,我们可以倍增预处理出从每个点跳天能跳到哪里,倍增跳跃的同时记录天数,时间复杂度
预处理倍增数字应先枚举,后枚举
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10; int a[N], st[N][25]; int main() { int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; int L, q; cin >> L >> q; for (int i = 1; i <= n; i++) st[i][0] = upper_bound(a + 1, a + n + 1, a[i] + L) - a - 1; for (int j = 1; j <= 20; j++) for (int i = 1; i <= n; i++) st[i][j] = st[st[i][j - 1]][j - 1]; while (q--) { int x, y, ans = 0; cin >> x >> y; if (x > y) swap(x, y); for (int i = 20; i >= 0; i--) if (st[x][i] < y) x = st[x][i], ans += (1 << i); cout << ans + 1 << "\n"; } return 0; }
- 1
信息
- ID
- 9524
- 时间
- 3000ms
- 内存
- 256MiB
- 难度
- 7
- 标签
- 递交数
- 53
- 已通过
- 13
- 上传者