T1 小苹果
题目描述
理论分析
对于第一问,我们按照题意模拟每天取走的是多少个苹果即可。由于每天可以取走原来的,数据范围没次会降低到,也就是说这样的过程的时间复杂度可以用下式表示:
对于本题的数据范围n<1e9,这个时间复杂度计算后在1e5左右,是可以接受的。
对于第二问,首先有一个很显然的结论是:第n个苹果会存在于从第一天开始的连续的若干天,然后在后面的天里不再存在。因此,我们可以维护一个bool类型的变量,作为最后一个苹果还在不在的判别。然后在每一天的判断过程中,我们通过整除关系可判别,这个苹果是不是被拿走。
代码实现
#include <bits/stdc++.h>
using namespace std;int main(){int n;cin>>n;int day=0, last=0;bool flag=false;while(n){day++;//是不是这天拿最后一个if(!flag&&(n-1)%3==0) flag=true, last=day;//这天结束,剩的苹果数n=n-(n-1)/3-1;}cout<<day<<" "<<last<<endl;return 0;
}
T2 公路
题目描述
理论分析
贪心即可!对于这个题目来说,一共要走的路程是一定的,所有一共加多少油也是确定的。不存在选择某种加油方案剩余油多,而选择另外的方案剩余油少的问题。因此,我们要做的就是让每升油的油价尽可能的低。那么问题来了,我们能不能都用最低油价买油呢?显然,当开始的0号位置油价最低时(题目中的1号,这里直接对应代码的编号说明了!下同),我们可以办到这件事,但是当1号节点油价并不是最低价的时候,我们需要首先走到油价最低的站点,那就至少需要在前面的节点买油。也就是说,假设处的油价最低,我们的问题就演变为了,首先求1号点到最低花多少钱,然后后半段直接用处的油价走完就行。那前半程的求解是一个数据范围比原问题更小的问题的求解。
我们当然可以像上述那样做递归的求解程序,只不过这样的时间效率是不高的,最差会来到,只能通过一半左右的样例。实际上上述贪心的过程等价于下面的贪心:我们从前往后考虑每个节点,维护需求加油的数量(只保证可以走到下一个节点)num,加完油后走到下个节点后会剩下多少油last,以及历史(已经过节点)的最低油价mn。对于每个节点,我们花费num*mn保证可以走到下一个节点。(也就是说,我们在拥有历史最低油价的那个点在原来的基础上多加num升油保证可以走到下一个点)。
代码实现
#include <bits/stdc++.h>
#define int long long
using namespace std;signed main(){int n, d;cin>>n>>d;int last=0;vector<int> v(n);vector<int> a(n);for(int i=0; i<n-1; i++) cin>>v[i];int ans=0, mn=0x3f3f3f3f, num;for(int i=0; i<n-1; i++){cin>>a[i];// 历史低价mn=min(mn, a[i]);// 至少需要多少才能走到下一个点num=(v[i]-last+d-1)/d;ans=ans+num*mn;// 油余量够走多远last=num*d-v[i]+last;}cout<<ans<<endl;return 0;
}
T3 一元二次方程
题目描述
理论分析
按照题意 老老实实模拟即可。需要注意的细节稍微有点多,但是细心一点也是可以一遍AC的!!
细节一:分数输出需要保证分母不是负数。
细节二:对于有两个解的情况而言,题中已经提示过中的,可以利用这一点简化代码的书写。
细节三:根号的化简要从大到小试探因数,这样更容易保证不重不漏。
细节四:根号内如果是完全平方数,那么最终结果将会不带有 “sqrt()” ,此时答案的化简需要自己分析好。
细节五:格式的答案,要注意格外第一项是不是0的判断。
大概就是这些细节吧。。。时间复杂度
代码实现
#include <bits/stdc++.h>
#define int long long
using namespace std;void print_sqrt(int s, int b, int a){int g=__gcd(b, a);pair<int, int> p;p.first=b/g;p.second=a/g;if(p.first<0) p.first*=-1;if(p.second<0) p.second*=-1;if(p.first!=1) cout<<p.first<<"*";cout<<"sqrt("<<s<<")";if(p.second!=1) cout<<"/"<<p.second;
}void print_int(int b, int a){int g=__gcd(b, a);pair<int, int> p;p.first=b/g;p.second=a/g;if(p.second<0){p.first*=-1;p.second*=-1;}if(p.second==1) cout<<p.first;else cout<<p.first<<"/"<<p.second;
}void solve(){int a, b, c, g;cin>>a>>b>>c;int delta=b*b-4*a*c;if(delta<0){cout<<"NO\n";}else if(delta==0){if(b==0) cout<<"0\n";else{print_int(-b, 2*a);cout<<"\n";}}else {bool flag=false;int num=1;for(int i=min(1000ll, delta-1); i>0; i--){if(i*i==delta){delta/=(i*i);num*=i;break;}else if(i*i<delta && delta%(i*i)==0){num*=i;delta/=(i*i);}}if(delta==1){if(a<0) print_int(-b-num, 2*a);else print_int(-b+num, 2*a);cout<<"\n";}else {if(b!=0) {print_int(-b, 2*a);cout<<"+";}print_sqrt(delta, num, 2*a);cout<<"\n";}}
}signed main(){int n, m;cin>>n>>m;while(n--){solve();}return 0;
}
T4 旅游巴士
题目描述
理论分析
这是一个分层图问题,即图上每个点要拆成个点。拆点的依据是原本的点 意义下的到达时间。我们使用表示到第i个点满足时间 的最短时间。初始条件为 ,然后跑最短路就行了。
相对难处理的点在于每条边经过的时间限制,对于这一点,我们可以原地等待k的倍数时间达成(其实相当于出发时间晚了k的倍数时间)。
代码实现
#include <bits/stdc++.h>
#define int long long
using namespace std;int ans[20005][100];
vector<vector<pair<int, int>>> g;signed main(){int n, m, k;cin>>n>>m>>k;g.resize(n+1);int u, v, a;while(m--){cin>>u>>v>>a;g[u].push_back(pair<int, int> (v, a));}for(int i=1; i<=n; i++)for(int j=0; j<k; j++) ans[i][j]=0x7f7f7f7f7f7f7f7f;queue<pair<int, int>> q;q.push(pair<int, int> (1, 0));ans[1][0]=0;int now, pos, need;while(!q.empty()){auto t=q.front();q.pop();for(int i=0; i<g[t.first].size(); i++){now=g[t.first][i].first;pos=(t.second+1)%k;need=ans[t.first][t.second];if(need<g[t.first][i].second) need=need+(g[t.first][i].second-need+k-1)/k*k;need++;if(ans[now][pos]==-1||need<ans[now][pos]){
// cout<<now<<" "<<pos<<" "<<need<<endl;ans[now][pos]=need;q.push(pair<int, int> (now, pos));}}}if(ans[n][0]>=0x7f7f7f7f7f7f7f7f) cout<<-1<<endl;else cout<<ans[n][0]<<endl;return 0;
}