Codeforces Round #321 (Div. 2) A B C D

本文介绍了Codeforces Round #321 (Div. 2)中A、B、C、D四道题目的解题思路。对于A题,通过排序和尺取法找到最长连续不递减子序列;B题利用无向图和节点度数判断叶子节点;C题采用状压动态规划方法解决,但在比赛中由于细节错误未能通过测试。作者提醒,状压dp要注意运算级别的问题。

A:找出最长连续不递减子序列....直接遍历寻找即可...

#include<bits/stdc++.h>
using namespace std;
int  a[110000];
int main()
{
    int n;
    scanf("%d",&n);
    a[0]=0;
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    int ans=0,tmp=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]>=a[i-1])
            tmp++;
        else
        {
            ans=max(ans,tmp);
            tmp=1;
        }
    }
    ans=max(ans,tmp);
    cout<<ans<<endl;
    return 0;
}
B.给定n个人,每个人有m(工资)和s(不知道是啥)两个属性,要求找到一个人的集合,这个集合内工资最多的人比工资最低的人的差值小于d,问所有可能集合内所有人的s属性和的最大值。

排序+尺取法

#include<bits/stdc++.h>
using namespace std;
#define ll long long
struct node
{
    int m,s;
}s[110000];
int cmp(node a,node b)
{
    return a.m<b.m;
}
int main()
{
    int n,d;
    cin>>n>>d;
    for(int i=1;i<=n;i++)
        scanf("%d %d",&s[i].m,&s[i].s);
    ll ans=0,ti=1,tj=1,tmp=0;
    sort(s+1,s+n+1,cmp);
    while(tj<=n)
    {
        while(s[tj].m-s[ti].m<d&&tj<=n)
        {
            tmp+=s[tj].s;
            tj++;
        }
        ans=max(ans,tmp);
        tmp-=s[ti].s;
        ti++;
    }
    ans=max(ans,tmp);
    cout<<ans<<endl;
    return 0;
}
C.给定一个点n,然后每个点的权值,只有0和1,1代表有猫,主角因为怕猫所以不能连续经过超过m个有猫的点,问主角能到达多少个叶子节点.根结点是1.

题目并没有说给的边是有向的,所以直接无向图建边,然后度数为1的除了可能是根以外就是叶子了..

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 110000
int head[N],t;
struct edge
{
    int u,v,next;
}edge[N*2];
int n,m,in[N],a[N],used[N];
void add(int u,int v)
{
    edge[t].v=v;
    edge[t].next=head[u];
    head[u]=t++;
}
int dfs(int u,int s)
{
    used[u]=1;
    if(a[u]==1) s++;
    else s=0;
    if(s>m) return 0;
    if(in[u]==1&&u!=1)
        return 1;
    int ans=0;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(used[v]==0)
        ans+=dfs(v,s);
    }
    return ans;
}
int main()
{
    memset(in,0,sizeof(in));
    memset(head,-1,sizeof(head));
    memset(used,0,sizeof(used));
    t=0;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    int u,v;
    for(int i=0;i<n-1;i++)
    {
        scanf("%d %d",&u,&v);
        add(u,v);
        add(v,u);
        in[u]++;
        in[v]++;
    }
    int ans=dfs(1,0);
    cout<<ans<<endl;
    return 0;
}

D,给定n个菜,每个菜都有一个美味值,然后支持m个菜,如果按照给定的k个规则吃会有额外的美味值加成,对于一个规则来说,u,v,w代表先吃u再吃v可以额外获得w,u v之间不能吃其他菜。

状压dp,dp[i][j]代表i这个状态下,最后一次吃的是j所能获得的最大美味值...

很久不写状压dp根本不会写了,手残写错了一个括号,成功没过题..赛后被人看出来,真是无语到爆,状压要注意运算级的问题。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 110000
ll dp[300000][20];
int a[20];
int mp[20][20];
int pd(int i)
{
    int ans=0;
    while(i)
    {
        ans+=i%2;
        i=i/2;
    }
    return ans;
}
int main()
{
    int n,m,k,u,v,w;
    scanf("%d %d %d",&n,&m,&k);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    memset(mp,0,sizeof(mp));
    for(int i=1;i<=k;i++)
    {
        scanf("%d %d %d",&u,&v,&w);
        u--;v--;
        mp[u][v]=w;
    }
    memset(dp,0,sizeof(dp));
    for(int i=0;i<n;i++)
        dp[1<<i][i]=a[i];
    ll ans=0;
    for(int i=1;i<(1<<n);i++)
    {
        if(pd(i)>m) continue;
        for(int j=0;(1<<j)<=i;j++)
        {
            if((i&(1<<j))==0)
                continue;
            int t=i-(1<<j);
            for(int k=0;(1<<k)<=t;k++)
            {
                if((t&(1<<k))==0) continue;
                dp[i][j]=max(dp[t][k]+a[j]+mp[k][j],dp[i][j]);
            }
        }
    }
    for(int i=1;i<(1<<n);i++)
    {
        if(pd(i)!=m) continue;
        for(int j=0;(1<<j)<=i;j++)
            ans=max(dp[i][j],ans);
    }
    cout<<ans<<endl;
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值