5.29花狮程设实训考试补题

第一题

洛谷原题(附上来源) 

食物链

P3183 [HAOI2016] 食物链 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

//1.食物链
#include<bits/stdc++.h>
using namespace std;
const int N = 114514;
vector<int> prey[N];//统计第i个生物的食物有哪些
int predator[N];//统计第i个生物有多少天敌(AOV网中节点的入度)
queue<int> trophic_level;//位于同一营养级的生物
int way[N];//到达某一个节点的路径(方案)数量
int bfs(){//网上说这个是topsort,但是我觉得说是bfs也未尝不可,求大佬指出区别
    int ans = 0;
    while(trophic_level.size()){
        int creature = trophic_level.front();
        trophic_level.pop();
        if(!prey[creature].size()){
            ans+=way[creature];
        }//如果没有食物,说明已经处于食物链底层,此时将以这个生物为终点的食物链加入到总的ans中
        for(auto p:prey[creature]){
            way[p] += way[creature];
            predator[p]--;//topsort思想,将top顶点移走
            if(!predator[p])trophic_level.push(p);//在移走所有天敌后将它入队,否则该生物多次入队
        }
    }
    return ans;
}
int main(){
    int n,m;cin>>n>>m;
    int a,b;//能量由a流向b
    for(int i = 1;i<=m;i++){
        cin>>a>>b;
        prey[a].push_back(b);//a以b为食
        predator[b]++;//b的天敌++
    }
    for(int i = 1;i<=n;i++){
        if(!predator[i]&&prey[i].size()){//食物链顶端生物没有天敌并且有被捕食生物
            trophic_level.push(i);
            way[i] = 1;
        }//让食物链顶端生物入队,并且将他们的way初始化为1
    }
    cout<<bfs();
    return 0;
}

碎碎念:

图论本蒟蒻刚学不久,这一道题卡了好久才ac,而且还是第一道题,太搞心态了。。。

top -k问题

一个结构体排序题目,网上oj找不到原题。

非递增子序列(Almost Increasing Subsequence)

 被自己傻笑了。。。

原来ac过的原题直接干,结果记错题目条件(子串可以不连续选取)wa了,小丑行为

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;

const int N = 114514*2;
int arr[N],prefix[N];//前缀和数组维护前面i项中连续三个数非递增出现的次数
int main(){
    int n,q;cin>>n>>q;
    for(int i = 1;i<=n;i++){
        cin>>arr[i];
    }
    for(int i = 3;i<=n;i++){
        prefix[i] = prefix[i-1];//前面i-1项中的非递增字串直接加上去
        if(arr[i-2]>=arr[i-1]&&arr[i-1]>=arr[i])prefix[i]++;//判断加上第i项之后能不能再形成一个非递增字串
    }
    int l,r;
    while(q--){
        cin>>l>>r;
        int ans = r-l+1;//特判不可能形成连续非增字串的情况
        if(r-l>1)ans-=(prefix[r]-prefix[l+1]);//每出现连续三个非增的数字,就少选其中一个,总数减去一
        cout<<ans<<endl;
    }
    return 0;
}

 这题的标答用的是前缀和,这是最优解(时间复杂度低一些),如果不熟悉还可以用vector数组维护非递增子串的位置;

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define ll long long
vector<ll> pos;

ll solve(int l,int r)
{
    return upper_bound(pos.begin(),pos.end(),r-1)-
    lower_bound(pos.begin(),pos.end(),l+1);//upper_bound和lower_bound返回值是迭代器(数组下标)可以以此算出非递增子串的数目
};
int main()
{
    int n,q;
    cin >>n >>q;
    vector<ll>a(n);
    for(int i=0;i<n; i++)
    {
        cin >>a[i];
    }
    for(int i=1;i+1<n; i++)
    {
        if(a[i-1]>= a[i]&& a[i]>= a[i+1])
        {
           pos.pb(i);//出现连续三个非递增的数字,就将中间元素的位置记录在vector中
        }
    }
    while(q--)
    {
        ll l,r;
        cin >>l >>r;
        l--;
        r--;
        if(r-l+1<=2)
        {
            cout<<r-l+1<< endl;
        }
        else
        {
            cout<<r-l+1-solve(l,r)<<endl;
        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值