A:水温

知识点:贪心

思路:其实调水温的操作可以看出:将序列分为若干段,使得:

  • 第一段的 s+∑xi 在 [L,R] 内。
  • 之后每一段 xi 前缀和的极差不大于 RL+1。

考虑贪心分段,每次都尽量往后推,直到不分段就导致不合法时再分段即可。

参考代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,s,L,R,ans;
struct node{
    int t,x;//在t时刻水温变化x 
}a[100001];
bool cmp(node a,node b){
    return a.t<b.t;//按照时间顺序排序 
}
signed main(){
    cin>>n>>s>>L>>R;
    for(int i=1;i<=n;i++){
        cin>>a[i].t>>a[i].x;
    }
    sort(a+1,a+1+n,cmp);
    int c=R-L+1;//温度差不能超过c 
    for(int i=1;i<=n;i++){
        if(a[i].t==a[i+1].t){//同一时刻温度的变化可以后续累加 
            a[i+1].x+=a[i].x;
            continue; 
        }
        s+=a[i].x;
        if(ans==0){//第一次 
            if(s<L||s>R){
                L=R=s;
                ans++;
                continue;
            } 
        }
        L=min(s,L),R=max(s,R);
        if(R-L+1>c){
            ans++;L=R=s;
        }
    } 
    cout<<ans;
    return 0;
}

B:打鼹鼠

知识点:贪心、动态规划

思路:首先时间是按照升序给出的,所以运用最长不下降子序列求解的思想,枚举 i 前面的每一只鼹鼠,如果可以从第 j 只鼹鼠的位置走到第 i 只鼹鼠的位置,那么就可以把第 i 只鼹鼠接到以第 j 只鼹鼠结尾的打鼹鼠序列上去,更新 ma。

那么怎样判断是否可以从第 j 只鼹鼠的位置走到第 i 只鼹鼠的位置呢?由于机器人不能斜着走,所以两只鼹鼠之间的距离就是 $∣x_i−x_j∣+∣y_i−y_j∣$。如果两只鼹鼠之间的距离小于等于 $t_i−t_j$,那么就走得到,反之就走不到。

参考代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,ans;
struct node{
    int t,x,y,num=1;
}a[1001];
int main(){
    freopen("da.in","r",stdin);
    freopen("da.out","w",stdout);
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>a[i].t>>a[i].x>>a[i].y;
        int ma=0;
        for(int j=1;j<i;j++){
            if(abs(a[i].x-a[j].x)+abs(a[i].y-a[j].y)<=a[i].t-a[j].t){
                ma=max(ma,a[j].num);
            }
        }
        a[i].num+=ma;
        ans=max(ans,a[i].num);
    }
    cout<<ans;
    return 0;
}

C:三角形牧场

知识点:动态规划

思路

首先考虑到dp[k][i][j]:表示用前k个木板是否能围成边长为i,j的三角形 
1、把第k个木板放在第i这条边里,那需要用前k-1个木板围成i-a[k]和j的三角形 dp[k-1][i-a[k]][j]
2、把第k个木板放在第j这条边里,那就需要用前k-1个木板围成i和j-a[k]的三角形 dp[k-1][i][j-a[k]]
3、把第k个木板放在第三条边中,那就需要用前k-1个木板围成i和j的三角形 dp[k-1][i][j] 
dp[k][i][j]=dp[k-1][i-a[k]][j]||dp[k-1][i][ja[k]]||dp[k-1][i][j] 
最后再次枚举每三条边的长度,看看符合三角形边长两边之和大于第三边,若满足,则求出最大值。

参考代码:

#include<bits/stdc++.h>
using namespace std;
int n,a[55],s;
double ans=-1;
bool dp[888][888]={1};
int main(){
    freopen("san.in","r",stdin);
    freopen("san.out","w",stdout);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        s+=a[i];//求周长 
    }
    for(int k=1;k<=n;k++){
        for(int i=s/2;i>=0;i--){
            for(int j=s/2;j>=0;j--){
                if(i-a[k]>=0&&dp[i-a[k]][j])dp[i][j]=1;
                if(j-a[k]>=0&&dp[i][j-a[k]])dp[i][j]=1;
            }
        }
    } 
    for(int i=s/2;i>0;i--){
        for(int j=s/2;j>0;j--){
            int k=s-i-j;
            if(!dp[i][j]||!(i+j>k&&i+k>j&&j+k>i)) continue;
            double p=s/2.0;
            ans=max(ans,sqrt(p*(p-i)*(p-j)*(p-(s-i-j))));
        }
    }
    if(ans!=-1)cout<<(long long)(ans*100);
    else cout<<ans;
    return 0;
}

D:两条道路

知识点:树形结构

思路:要先编出两条路径之积,就得先编出一条最长路径的方法,很显然是树的直径。 这时候我们就要想了,如果是两棵树,我们就可求出结果。 对了,我们可以暴力每一条边,在建树时删去这条边,从而建成两棵树。 建出两棵树后,我们就可以做两次树的直径,求出两条路径之长,从而算出结果。

参考代码:

#include<bits/stdc++.h>
using namespace std;
int n,x[201],y[201],dp[201],s,sum,ans;
vector<int> v[201]; 
void dfs(int f,int p){
    for(int i=0;i<v[f].size();i++){
        int g=v[f][i];
        if(g==p)continue;
        dfs(g,f);
        sum=max(sum,dp[f]+dp[g]+1);
        dp[f]=max(dp[f],dp[g]+1); 
    }
} 
int main(){
    cin>>n;
    for(int i=1;i<n;i++){
        cin>>x[i]>>y[i];
        v[x[i]].push_back(y[i]);
        v[y[i]].push_back(x[i]);
    }//断开第i条边看看 
    for(int i=1;i<n;i++){
        memset(dp,0,sizeof dp);
        s=1,sum=0;
        dfs(x[i],y[i]);
        s*=sum;sum=0;
        memset(dp,0,sizeof dp);
        dfs(y[i],x[i]);
        s*=sum;sum=0;
        ans=max(s,ans); 
    }
    cout<<ans;
    return 0;
}
Copyright ©图灵之星 2024,转载需注明出处该文件修订时间: 2025-09-13 21:47:20

results matching ""

    No results matching ""