第一题
洛谷原题(附上来源)
食物链
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;
}
}
}