长沙学院2022暑假训练赛(一)ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛牛客竞赛OJ (nowcoder.com)

长沙学院2022暑假训练赛(一)ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛牛客竞赛OJ (nowcoder.com)

1.B-富婆价值最大化!_长沙学院2022暑假训练赛(一) (nowcoder.com)

dp题。

考虑用sum表示前缀和,cntmin表示前缀和最小值数量,summin表示前缀和最小值,mx表示最大子段和

三种情况。

1.sum[i]-summin>mx dp[i]=cntmin 2.sum[i]-summin=mx dp[i]=cntmin+dp[i-1] 3.sum[i]-summin<mx dp[i]=dp[i-1]

#include<bits/stdc++.h>
using namespace std;
#define fel(i,x,y) for(int i=x;i<=y;i++)
#define feh(i,x,y) for(int i=x;i>=y;i--)
#define int long long
#define pb push_back
#define IOS cin.tie(0)->sync_with_stdio(false);
//考虑用sum表示前缀和,cntmin表示前缀和最小值数量,summin表示前缀和最小值,mx表示最大子段和
//sum[i]-summin>mx dp[i]=cntmin
//sum[i]-summin=mx dp[i]=cntmin+dp[i-1]
//sum[i]-summin<mx dp[i]=dp[i-1]
const int N=1e6+100;
int n,a[N],dp[N],m;
signed main(){
IOS
cin>>n>>m;
fel(i,1,n){
cin>>a[i];
a[i]+=a[i-1];
}
int cntmin=1,summin=0,mx=-1e18;
for(int i=1;i<=n;i++){
if(a[i]-summin>mx){
dp[i]=cntmin;
mx=a[i]-summin;
}
else if(a[i]-summin==mx){
dp[i]=cntmin+dp[i-1];
}
else{
dp[i]=dp[i-1];
}
if(a[i]<summin){
summin=a[i];
cntmin=1;
}
else if(a[i]==summin){
cntmin++;
}
}
while(m--){
int k;
cin>>k;
cout<<dp[k]<<endl;
}
return 0;
}

 

2.C-异世界_长沙学院2022暑假训练赛(一) (nowcoder.com)

题目确实有些小奇怪//要求再保证到达x据点的前提下最短步数最小值是不变的。 这就必须的得保证每次都是走的边数都必须时相同的

然后考虑二分,考虑建边时间的最大值。

#include<bits/stdc++.h>
using namespace std;
#define fel(i,x,y) for(int i=x;i<=y;i++)
#define feh(i,x,y) for(int i=x;i>=y;i--)
#define ll long long
#define pb push_back
#define IOS cin.tie(0)->sync_with_stdio(false);
#define inf 0x7fffffff
#define endl "\n"
const int N=2e5+100;
int n,k,x,a[N],m;
int cnt,head[N],dis[N];
struct node{
int to,next,w;
}b[N*2];
void add(int from,int to,int w){
b[++cnt].to=to;
b[cnt].w=w;//这是修路的时间
b[cnt].next=head[from];
head[from]=cnt;
}
int bfs(int mx){//建边的最大时间
queue<int>q;
for(int i=1;i<=n;i++){
dis[i]=inf;
}
for(int i=1;i<=k;i++){
q.push(a[i]);
dis[a[i]]=0;
}
while(!q.empty()){
auto now=q.front();
q.pop();
for(int i=head[now];i;i=b[i].next){
int j=b[i].to;
if(dis[j]!=inf||b[i].w>mx) continue;//如果此点已到或者这条边的修建时间大于mx
dis[j]=dis[now]+1;
q.push(j);
}
}
return dis[x];
}
int main(){
   IOS
cin>>n>>k>>x;
fel(i,1,k) cin>>a[i];
cin>>m;
fel(i,1,m){
int x,y,w;
cin>>x>>y>>w;
add(x,y,w);
add(y,x,w);
}
int ans=bfs(1e9);
if(ans==inf){
cout<<-1<<endl;
return 0;
}
int l=0,r=1e9,res=0;
while(l<=r){
int mid=l+r>>1;
if(bfs(mid)<=ans) res=mid,r=mid-1;//最小步数必须不变
else l=mid+1;
}
cout<<ans+res<<endl;
return 0;
}

3.E-Beautiful path_长沙学院2022暑假训练赛(一) (nowcoder.com)

其实学过树形dp这还是个很简单的题的。

分别求比他的大的最长path和比他小的最长path

#include<bits/stdc++.h>
using namespace std;
#define fel(i,x,y) for(int i=x;i<=y;i++)
#define feh(i,x,y) for(int i=x;i>=y;i--)
#define int long long
#define pb push_back
#define IOS cin.tie(0)->sync_with_stdio(false);
const int N=1e6+100;
//没学过这种树上的dp
//当时想这么大的数据范围咋dp
//这么大的数据范围咋过的?????
//图上的dp是个什么玩意
//分别求比他的大的最长path和比他小的最长path
int n,dp[N][2],a[N],ans;
vector<int>b[N];
void dfs(int now,int fa){
dp[now][0]=dp[now][1]=1;
for(auto i:b[now]){
if(i==fa) continue;
dfs(i,now);
if(a[i]>a[now]){
dp[now][0]=max(dp[i][0]+1,dp[now][0]);
}
if(a[i]<a[now]){
dp[now][1]=max(dp[now][1],dp[i][1]+1);
}
}
ans=max(ans,dp[now][0]+dp[now][1]-1);
}
signed main(){
   IOS
cin>>n;
for(int i=1,x,y;i<n;i++){
cin>>x>>y;
b[x].pb(y);
b[y].pb(x);
}
fel(i,1,n) cin>>a[i];
dfs(1,0);
cout<<ans<<endl;
}

4.F-平面最小距离_长沙学院2022暑假训练赛(一) (nowcoder.com)

二分题,就是考虑如何求第n个菱形的点数 和 求当前菱形增加点何时最大距离变成了下一个菱形的最大值。

#include<bits/stdc++.h>
using namespace std;
#define fel(i,x,y) for(int i=x;i<=y;i++)
#define feh(i,x,y) for(int i=x;i>=y;i--)
#define int long long
#define pb push_back
#define IOS cin.tie(0)->sync_with_stdio(false)
//要在O(1)的时间求第mid个菱形的大小,公式是(1+3+5)*2+7,这是第四个个菱形的大小
//然后每个菱形只要个数是大于ai(表示第i个奇数)最大距离就会变成下一个整数
int sum(int x){
int a1=1;
int an=2*x-1;
return (a1+an)*x-an;
}
signed main(){
   //cout<<sum(4)<<endl;
int n;
int l=0,r=1e9;
int ans=-1;
cin>>n;
while(l<=r){
int mid=l+r>>1;
if(n>=sum(mid)&&n<sum(mid+1)){
if(n-sum(mid)<=2*mid-1){
ans=2*mid-1;
}
else{
ans=2*mid;
}
break;
}
else if(n<sum(mid)){
r=mid-1;
}
else if(n>sum(mid)){
l=mid+1;
}
//         cout<<l<<r<<endl;
//         cout<<mid<<endl;
}
   if(ans==0){
       cout<<1<<endl;
  }
   else{
       cout<<ans<<endl;  
  }
   return 0;
}

5.G-恩赐_长沙学院2022暑假训练赛(一) (nowcoder.com)

会个multipset的lowerbound就能过。

prev访问迭代器的上一个点,next访问下一个。

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define int long long
const int N=2e5+100;
int n,m,k,h,a;
multiset<int>s;
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a,s.insert(a);
while(m--){
cin>>k>>h;
auto it=s.lower_bound(k);
if(it==s.begin()) continue;
int x=*prev(it);//prev就是把指针往前移动一位,next是往后移动一位,内部是有序的
s.erase(prev(it));
s.insert(x+h);
}
cout<<*s.rbegin()<<endl;//为什么不能是end呢?
return 0;
}
 
posted @ 2022-08-22 11:37  silky__player  阅读(64)  评论(0)    收藏  举报