文章目录
题314.csp-2203 P1未初始化警告&P2出行计划&P3计算资源调度器
一、P1未初始化警告
1.题目
2.题解
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+1;
int n,k;
int flag[maxn];
int cnt;
int main()
{
cin>>n>>k;
for(int i=0;i<k;i++)
{
int x,y;
cin>>x>>y;
if(y!=0&&!flag[y])//ay不是常量且ay未被赋值
{
cnt++;//未初始化变量数++
}
flag[x]=1;
}
cout<<cnt;
}
二、P2出行计划
1.题目
2.题解
本题给定n个出行的开始时间ti以及出行对应地点需持ci时间内的核酸检测,求对于m个核酸检测时间点询问,在k时间出结果以后最多出行的个数。
暴力求解,十分显然,无非就是对于每次询问,把可出行的时间的上界与下界通过k,q,c算出来,看开始出行时间t是否在那个时间区间内就好,这样每次询问得做n次计算,对于m次询问,时间复杂度自然是平方级别的,不满足本题满分的要求。
对于本题的正解,我们可以用差分+前缀和。如何想到的?易知,暴力解法,每个出行点可出行需满足的条件为q+k<=ti<=q+k+ci-1,这个条件不是很好用,我们不妨将其变形,化成ti-ci-k+1<=q<=ti-k,推导过程如下:
则问题就变为了看q这个点能够被放在多少个[t-c-k+1,t-k]区间里,但是单纯这样去想又会发现每次询问仍然要拿着q对那n个区间去比对,时间和原先暴力解法一样。此时我们不妨转换思考的角度,看q这个点能够被放在多少个[t-c-k+1,t-k]区间里这个问题其实等价于用n个区间把一堆时间点给覆盖了,看问的那个时间点被多少个区间所覆盖的问题。
这样我们其实可以在输入n个出行点信息的时候把对应区间求出,然后把这个区间内所有的时间点对应的结果(即被覆盖数,原先为0)都+1,然后在后面询问的时候,直接输出那个时间点对应的结果就好。那么如何可以快速的将一个区间内的值进行统一的修改呢?显然就会想到差分了。对于给定结果数组对应的差分数组b[l]+1,b[r+1]-1,等价于对其原数组,即结果数组cnt[l~r]+1。之后做完输入操作之后,求前缀和得到结果数组就好。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+2;
int n,m,k;
int cnt[maxn],b[maxn];//结果数组,结果数组对应的差分数组
int main()
{
cin>>n>>m>>k;
int maxr=0;
for(int i=0;i<n;i++)
{
int t,c;
cin>>t>>c;
int l=t-c-k+1,r=t-k;//确定区间左端点与右端点
maxr=max(maxr,r);
//设结果对应的差分数组,用于对[l,r]做区间修改(cnt[l~r]+1,即覆盖该范围的区间个数+1,对应对b[l]+=1,b[r+1]-=1)
b[max(1,l)]+=1;//因为l可能为非正数,此时该区间覆盖的点最小显然可从1开始
b[max(r,0)+1]-=1;//因为r可能为非正数,此时该区间覆盖的点最大显然可到1
}
for(int i=1;i<=maxr;i++)//对差分数组求前缀和得到结果数组
{
cnt[i]=cnt[i-1]+b[i];
}
for(int i=0;i<m;i++)
{
int q;
cin>>q;
cout<<cnt[q]<<endl;//对结果数组做单点询问,得到结果
}
}
三、P3计算资源调度器
1.题目
2.题解
#include <bits/stdc++.h>
using namespace std;
const int maxn=1100;
struct Node//计算节点
{
int id;//节点编号
int field;//节点所属可用区
int tasknum;//节点运行的任务数量
} node[maxn];
unordered_map<int,set<int>> appfield;//应用i放置的可用区
unordered_map<int,set<int>> appnode;//应用i放置的计算节点的id
int n,m;
void init()//计算节点初始化
{
for(int i=1; i<=n; i++)
{
int field;
cin>>field;
node[i].id=i;
node[i].field=field;
node[i].tasknum=0;
}
}
vector<Node> select(int a,int na,int pa,int paa,int paar)//节点筛选:得到a应用对应的其中一个任务的可选任务节点
{
vector<Node> res,tmp;
for(int i=1; i<=n; i++) res.push_back(node[i]);//先把所有计算节点当作可选选入
if(na>0)//节点亲和性过滤
{
for(auto it=res.begin(); it!=res.end(); )
{
if((*it).field!=na) res.erase(it);//可用区得是na的计算节点才能被保留
else it++;
}
}
if(pa>0)//任务亲和性过滤
{
for(auto it=res.begin(); it!=res.end(); )
{
if(appfield[pa].find((*it).field)==appfield[pa].end()) res.erase(it);//pa应用有的计算节点才能被保留
else it++;
}
}
if(paa>0)//任务反亲和性过滤
{
for(auto it=res.begin(); it!=res.end(); )
{
if(appnode[paa].find((*it).id)!=appnode[paa].end())//paa应用没有的计算节点才能被保留
{
tmp.push_back(*it);//暂存过滤节点
res.erase(it);
}
else it++;
}
if(res.size()==0&&paar==0)//如果过滤完一个节点都没有了,则看看是不是只是尽量满足任务反亲和
{
for(int i=0; i<tmp.size(); i++) res.push_back(tmp[i]);//把过滤掉的节点塞回去
}
}
return res;
}
int main()
{
cin>>n>>m;
init();
int g;cin>>g;
while(g--)
{
int f,a,na,pa,paa,paar;
cin>>f>>a>>na>>pa>>paa>>paar;
for(int i=0; i<f; i++)//按照题目说的启动一组(f,...)和启动f组(1,...)是一样的,所以直接做f次计算节点筛选操作
{
vector<Node> res=select(a,na,pa,paa,paar);//节点筛选
if(res.size()>0)
{
//得到任务数最少且编号最小的节点
Node resnode={maxn,0,2000};
for(int i=0; i<res.size(); i++)
{
if(res[i].tasknum<resnode.tasknum) resnode=res[i];
else if(res[i].tasknum==resnode.tasknum&&res[i].id<resnode.id) resnode=res[i];
}
//更新节点使用情况
for(int i=1; i<=n; i++)
{
if(node[i].id==resnode.id)
{
node[i].tasknum++;
appfield[a].insert(node[i].field);
appnode[a].insert(node[i].id);
break;
}
}
cout<<resnode.id<<" ";
}
else cout<<"0"<<" ";
}
putchar('\n');
}
}
四、P4通信系统管理
1.题目
2.题解
//运行超时,10分
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,ll> pil;
const int maxn=1100;
struct Info
{
int u,v;
int x;
int deadline;
};
int n,m;
vector<Info> table;
ll G[maxn][maxn];
void update(int d)
{
for(auto info:table)
{
if(d==info.deadline) G[info.u][info.v]-=info.x,G[info.v][info.u]-=info.x;
}
}
void apply(int d,int u,int v,int x,int y)
{
table.push_back({u,v,x,d+y});
G[u][v]+=x,G[v][u]+=x;
}
int check(int u)
{
int ans=0;
for(int v=1;v<=n;v++)
{
if(u==v) continue;
if(G[u][v]>G[u][ans]) ans=v;
}
return ans;
}
void queryIslandNum()
{
int cnt=0;
for(int u=1;u<=n;u++)
{
int flag=0;
for(int v=1;v<=n;v++)
{
if(u==v) continue;
if(G[u][v])
{
flag=1;
break;
}
}
if(!flag) cnt++;
}
cout<<cnt<<endl;
}
void queryRelNum()
{
int cnt=0;
int rel[maxn];
for(int u=1;u<=n;u++)
{
rel[u]=check(u);
}
for(int u=1;u<=n;u++)
{
int v=rel[u];
if(rel[v]==u) cnt++;
}
cout<<cnt/2<<endl;
}
int main()
{
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=0;i<m;i++)
{
update(i);
int k;cin>>k;
while(k--)
{
int u,v,x,y;
cin>>u>>v>>x>>y;
apply(i,u,v,x,y);
}
int l;cin>>l;
while(l--)
{
int u;cin>>u;
cout<<check(u)<<endl;
}
int p,q;
cin>>p>>q;
if(p) queryIslandNum();
if(q) queryRelNum();
}
}