2022/1/26

142 篇文章 1 订阅
92 篇文章 0 订阅

p4998

计算所有点的不合理值取前k个相加就可以,,难点是有可能是负数,则我们就全加一倍变为正数,还要计算每个点的不合理值,如果生算的话必定会超时,用前缀和,计算下一个点时,上一个点的前缀和会有什么变化呢?这个点左边的值距离都会+1,而右边的值都会减1,根据这个求出所有点距离的前缀和,最后取前k小就可以了

题解 P4998 【信号站】 - RenaMoe's blog - 洛谷博客 (luogu.com.cn)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const int L=1e6;
ll n,k,a[2000005],sum[2000005],l,r,ans=0;
int main(){
    //freopen("in.txt","r",stdin);
    cin>>n>>k;
    ll x;
    for(int i=1;i<=n;i++) cin>>x,a[x+L]++;
    for(int i=0;i<=L+L;i++){sum[0]+=a[i]*i;}
    r=n;
    for(int i=1;i<=L+L;i++){
        l+=a[i-1];//累加左边的个数
        sum[i]=sum[i-1]+l-r;//更新前缀和
        r-=a[i];//累减右边的个数
    }
    sort(sum,sum+L+L+1);
    for(int i=0;i<k;i++) ans+=sum[i];
    cout<<ans<<endl;
    return 0;
}

p5603 拓扑排序

最劣情况属实折磨我了,并不是一个简简单单的倒序就可以的,所以可以再开一个队列,队列就行不需要单调的,来存放小值,大值就继续压进优先队列中,这样可以把最大的给输出,这样后面的数就不可能会使得ans++了,反例看看这个博客 

题解 P5603 【小C与桌游】 - Mubuky 的博客 - 洛谷博客 (luogu.com.cn)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const int L=1e6;
int n,m,u,y,in1[500005],in2[500005];
vector<int>v1[500005],v2[500005],v;
priority_queue<int,vector<int>,greater<int> >q1;
priority_queue<int,vector<int>,less<int> >q2;
queue<int>q3;
void topo1(){
    v.clear();
    for(int i=1;i<=n;i++)
        if(in1[i]==0) q1.push(i);
        while(!q1.empty()){
            int p=q1.top();q1.pop();
            v.push_back(p);
            for(int i=0;i<v1[p].size();i++){
                int y=v1[p][i];
                in1[y]--;
                if(in1[y]==0) q1.push(y);
            }
        }
        int maxx=0,ans=0;
            for(int i=0;i<v.size();i++){
                if(v[i]>maxx) ans++,maxx=v[i];
            }
            cout<<(ans>1919810?1919810:ans)<<endl;
}
void topo2(){
    int maxx=0,ans=0;
    for(int i=1;i<=n;i++)
        if(in2[i]==0) q2.push(i);
    while(!q2.empty()){
        int p=q2.top();
        if(p>maxx) ans++;
        while(!q2.empty()){
            q3.push(q2.top());
            q2.pop();
        }
        while(!q3.empty()){
            int x=q3.front();
            q3.pop();
            maxx=max(maxx,x);
            for(int j=0;j<v2[x].size();j++){
                int y=v2[x][j];
                in2[y]--;
                if(in2[y]==0){
                    if(y>maxx) q2.push(y);//这样最后从q2出来的就会是最大值,这样后面的就不会使得ans++了
                    else q3.push(y);//小数就继续压进q3,因为这对ans没有影响了,不需要特殊处理
                }
            }
        }//其实就是借助q3把最大值尽可能地放在了前面,小值就直接在q3里pop掉了
    }
            cout<<(ans>1919810?1919810:ans)<<endl;
}
int main(){
       //freopen("in.txt","r",stdin);
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>u>>y;
        v1[u].push_back(y);
        v2[u].push_back(y);
        in1[y]++;
        in2[y]++;
    }
    topo1();
    topo2();
    return 0;
}

CF1389B Array Walk

话说这是黄题吗?好难。。。dp[i][j]代表向左走了i步,在位置j时的最大分数,第一重循环z因为这样可以知道所有位置的所有情况,其次再循环n,最后k可以根据k=i*2+j-1来判断;其实知道怎样设状态怎样循环后,这个转移方程还是比较好想的,dp[i][j]=max(dp[i][j],dp[i+1][j-1]+a[i]);

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const int L=1e6;
ll t,n,k,z,dp[100005][7],a[100005];
int main(){
       //freopen("in.txt","r",stdin);
       cin>>t;
       while(t--){
        cin>>n>>k>>z;
        ll maxx=0;
        for(int i=1;i<=n;i++) cin>>a[i];
        for(int j=0;j<=z;j++)
        for(int i=1;i<=n;i++){
            dp[i][j]=dp[i-1][j]+a[i];
            if(j&&i!=n) dp[i][j]=max(dp[i][j],dp[i+1][j-1]+a[i]);
            if(i-1+j*2==k) maxx=max(maxx,dp[i][j]);
        }
        cout<<maxx<<endl;
       }
    return 0;
}

p6033 runtime队列

这题目本身已经不重要了,困扰我两个小时的原因时我自己写的代码runtime了,至于为何,在这里记录一下,队列没有元素还要他弹出元素也是会runtime的!!!!!!!!!!!!!

p6155 

2的64次方取模就用unsigned ,相同的数就压进栈,然后再弹出栈计算进栈和出栈相差的时间,对这个事件排序按小到大乘以bi就可以了,虽然我对这题毫无思路。。。。

T3-修改 - gyh20 的博客 - 洛谷博客 (luogu.com.cn)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,p[1000005],a[1000005],b[1000005];
unsigned long long ans;
struct node{
    ll v,xu;
};
stack<node>q;
bool cmp(ll a,ll b){
    return a>b;
}
int main(){
    //freopen("in.txt","r",stdin);
    scanf("%lld",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
    sort(b+1,b+n+1);
    ll l=1,x=1;
    while(1){
        if(q.empty()){
            if(l<=n) x=a[l];
            else break;
        }
        while(a[l]==x){
            q.push(node{a[l],l});
            l++;
        }
        node tmp=q.top();
        q.pop();
        p[tmp.xu]=x-tmp.v;//计算出栈和进栈相差的时间
        x++;
    }
    sort(p+1,p+n+1,cmp);
    for(int i=1;i<=n;i++)ans+=p[i]*b[i];
    cout<<ans<<endl;
    return 0;
}

p6397 二分

这道题的check函数难想,我们一开始先让d[1]加上mid,然后看看能否与下一个的距离小于等于k,然后我们先让1号和2号同时向右走一段时间,然后再让1号自己向右走正好与2号的距离为k,这样可以卡2号的极限距离,看其是否能走到与3号相差k,走不到就尽量走,之后的也一样

题解 P6397 【[COI2008] GLASNICI】 - Eclosion 的博客 - 洛谷博客 (luogu.com.cn)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n;
double k,d[100005];
bool check(double mid){
    double maxx=d[1]+mid;
    for(int i=2;i<=n;i++){
        if(d[i]-mid-maxx>k) return 0;
        maxx+=k;
        if(d[i]+mid<maxx) maxx=d[i]+mid;
    }
    return 1;
}
int main(){
    //freopen("in.txt","r",stdin);
    cin>>k>>n;
    for(int i=1;i<=n;i++) cin>>d[i];
    double l=0,r=d[n],mid;
    while(r-l>=0.000001){
        mid=(l+r)/2.0;
        if(check(mid)) r=mid;
        else l=mid;
    }
    cout<<fixed<<setprecision(4)<<l<<endl;
    return 0;
}

p6433 dp

最后说一遍我是傻逼,看题解还能看错;当所有时间加起来小于m就是贪心,加不起来就是动态规划,这个是加了重循环,翻倍的那个循环,最后一定要判断谁不加倍谁加倍更好

题解 P6433 【「EZEC-1」出题】 - QwQ - 洛谷博客 (luogu.com.cn)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,k,dp[1005][110],ans=0,sum=0;
struct poi{
    int d,x;
}a[1005];
bool cmp(poi a,poi b){return a.d>b.d;}
int main(){
    //freopen("in.txt","r",stdin);
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++) cin>>a[i].d>>a[i].x,sum+=a[i].x;
    if(sum<=m){
        sort(a+1,a+n+1,cmp);
        for(int i=1;i<=k;i++) ans+=a[i].d*2;
        for(int i=k+1;i<n;i++) ans+=a[i].d;
        cout<<ans<<endl;
        return 0;
    }
    for(int i=1;i<=n;i++)
    for(int j=m;j>=a[i].x;j--){
        for(int l=k;l>=1;l--){
        dp[j][l]=max(dp[j][l],max(dp[j-a[i].x][l]+a[i].d,dp[j-a[i].x][l-1]+a[i].d*2));
        ans=max(ans,dp[j][l]);
        }
        dp[j][0]=max(dp[j][0],dp[j-a[i].x][0]+a[i].d);
        ans=max(ans,dp[j][0]);
    }
    cout<<ans<<endl;
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

killer_queen4804

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值