A 大佬的生日大礼包
https://ac.nowcoder.com/acm/contest/53548/A
思路:
根据题意 发现答案呈单调性 即最多可以发放k份物品 则一定可以发放(0,k)件物品,则可以使用二分 来归并到 答案。那么我们只需要一个 check(p) 函数判断 答案p 是否可行即可。发现 三个礼包都减去一个u盘和一个鼠标,则 豪华礼包剩一个键盘,幸运礼包剩一个 鼠标,普通礼包剩一个u盘,满足 区分性。因为 希望相邻的参赛选手拿到的礼包类型都不同,则易证明 每种礼包类型不能超过 P/2。每种礼包最多能为答案贡献为 min(该礼包个数,P/2);
代码
bool check(ll a,ll b,ll c,ll k){
a=a-k;b=b-k;
if(a<0||b<0)return false;
ll cnt=0;
ll kk=(k+1)/2;
cnt=cnt+min(a,kk);
cnt+=min(b,kk);
cnt+=min(c,kk);
if(cnt>=k)return true;
else return false;
}
B 圣诞节糖果
https://ac.nowcoder.com/acm/contest/53548/B
思路:
根据题意 我们只需要选择两堆糖果,然后 可以获得两堆糖果总数对p取模的余数的个数。暴力做法 就是两个for 循环即可,但 因为 n的数据范围是(2,1e5) 所以会超时,但是我们可以发现我们将n堆糖果对p取余 之后排序,就可以 发现 当遍历到第i堆糖果的时候,因为 都需要对p取余,所以我们可以发现,当两堆糖果 个数总和大于P的时候 一定是小于等于a[i]的,所以我们对我们贡献最大的就是两堆之和小于等于P的,并且需要满足尽可能大,满足单调性,即存在 一个a[j])为答案时,必然是存在所有a[k]+a[i]<=P k属于(i+1,j-1)都是小于等于P的,且必然存在 所以a[s]+a[i]>P s属于(j+1,n)。
代码
for(int i=1;i<=n;i++){
ll l=i+1,r=n;
while(l<r){
ll mid=(l+r+1)>>1;
if(a[i]+a[mid]<p)l=mid;
else r=mid-1;
}
if(i<r)maxx=max(maxx,(a[i]+a[r])%p);
}
C 最优乘车
https://ac.nowcoder.com/acm/contest/53548/C
思路:
就是一个简单的最短路问题,难点在与 建图方式,因为我们需要求从饭店到S公园的过程中换车的次数最少,类似求闭包,我们可以将所有公交路线上的车能互相到达的车站都连一条边,等同于 保证在同一条公交路线最多只走一次,所以 最终的最短路距离减-1 就是换乘次数。
int main(){
int m,n;cin>>m>>n;
vector<vector<int>>v(n+10);
string s;getline(cin,s);
for(int i=0;i<m;i++){
getline(cin,s);int sum=0;
for(int j=0;j<s.size();j++){
if(s[j]==' ') v[i].push_back(sum),sum=0;
else sum=sum*10+s[j]-'0';
}
v[i].push_back(sum);
}
for(int i=0;i<m;i++){
for(int j=0;j<v[i].size();j++){
for(int k=j+1;k<v[i].size();k++){
f[v[i][j]][v[i][k]]=1;
}
}
}
memset(dist,0x3f,sizeof(dist));
queue<int>q;q.push(1);dist[1]=0;
while(q.size()){
int k=q.front();q.pop();
for(int i=1;i<=n;i++){
if(f[k][i]&&dist[i]>dist[k]+1){
dist[i]=dist[k]+1;q.push(i);
}
}
}
if(dist[n]==0x3f3f3f3f)cout<<"NO"<<endl;
else cout<<max(dist[n]-1,0)<<endl;
return 0;
}
D 小H和游戏
https://ac.nowcoder.com/acm/contest/53548/D
思路:
阅读题意 发现每次轰炸都会波及到与该城市距离不超过2的城市。 可以对每个点 维护三个信息,该点被轰炸的次数,该点儿子被轰炸的次数,该点孙子被轰炸的次数。然后 就可以类比到 题目要求 每次 该城市被轰炸,会影响到的点为,该点的儿子 该点的孙子,该点的父亲,该点父亲的儿子,该点父亲的父亲。 记录答案为 该点被轰炸的次数+该点父亲的儿子被轰炸的次数+该点父亲的父亲的孙子被轰炸的次数。 所以我们只需要预处理一下找到每个人 的父亲是谁就行,做一遍dfs 即可。
代码
void dfs(ll u,ll fa){
f[u]=fa;
for(int i=h[u];i!=-1;i=ne[i]){
ll j=e[i];