L. Project Manager【思维+STL(2400

Problem - L - Codeforces

应该这么想:要维护每天哪些人干哪些活,那我可以直接维护每天哪些人干了哪些项目吗,{int,vector<int>}但题目有个条件,每个人都干优先级最高的事情,所以后面直接vector不好做,信息不能合在一起维护,所以拆开,一个维护每个人手头上(即当前)的blocking项目数,另一个维护每个人手头上(即当前)的项目有哪些——这样分开来维护就能实现当某个人完成一个任务的时候也能确定他完成的是哪个project了(因为后者用set维护);

注意到需要维护的主体之间的关系是:工作——人,人——时间(枚举时间)

到这里实际上主要的功能就结束了,接下来想如何维护刚才的两个东西——得有一个vector<>del记录删了哪些project,这样好每天结束之后更新每个人的项目数和有哪些项目;得有个lst指针记录每个project的part进行到哪了;同时因为人是受时间轴限制而工作不受限,所以直接开7个向量存每个人手头上(即当前)的blocking项目数,维护这7天的每天;后者每个人手头上(即当前)的项目有哪些并不需要,独立于时间轴;

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+15;
const int mo = 998244353;
#define pb push_back
#define pii pair<int,int>
#define ft first
#define sd second
#define debug1(x) cerr<<"! "<<x<<endl;
#define debug2(x,y) cerr<<"#  "<<x<<" "<<y<<endl;

void slv(){
	int n,m,k;cin>>n>>m>>k;
	map<string,int>wdy;//whichday
	wdy["Monday"]=0; wdy["Tuesday"]=1; wdy["Wednesday"]=2;
	wdy["Thursday"]=3; wdy["Friday"]=4; wdy["Saturday"]=5; wdy["Sunday"]=6;
	vector<vector<int>>wkd(n,vector<int>(7));//is_workday?
	for(int i=0;i<n;i++){
		int nm;cin>>nm;
		for(int j=0;j<nm;j++){
			string tmp;cin>>tmp;
			wkd[i][wdy[tmp]]=1;
		}
	}
	set<int>ihy;//isholidays?
	for(int i=0;i<m;i++){
		int x;cin>>x;x--;ihy.insert(x);
	}
	vector<vector<int>>p(k);//which part?
	for(int i=0;i<k;i++){
		int nm;cin>>nm;
		p[i].resize(nm);
		for(int &k:p[i]){
			cin>>k;k--;//check
		}
	}
	//因为你并不知道这个人是第什么时候做这个项目
	vector<map<int,int>>cur(7);//which day,which one,do how much things
	vector<set<int>>wk(n);//worker
	vector<int>lst(k),ans(k);

	for(int i=0;i<k;i++)for(int j=0;j<7;j++)if(wkd[p[i][0]][j]){
		cur[j][p[i][0]]++;
	}
	for(int i=0;i<k;i++){
		wk[p[i][0]].insert(i);//这个映射关系我想了很久
	}

	int done=0;
	for(int d=0;;d++){//for_day
		if(ihy.count(d)){
			continue;
		}
		int nd=d%7;//nowday
		vector<int>nwr,del;//now_worker  del_project
		for(auto k:cur[nd]){
			nwr.pb(k.ft);
		}
		for(auto x:nwr){
			for(int i=0;i<7;i++){
				auto it=cur[i].find(x);
				if(it!=cur[i].end()){
					if(it->sd==1)
						cur[i].erase(it);
					else
						--it->sd;				
				}
			}
			int y=*wk[x].begin();
			del.pb(y);
			wk[x].erase(wk[x].begin());
		}
		int sz=nwr.size();
		for(int i=0;i<sz;i++){
			int y=del[i];
			lst[y]++;
			if(lst[y]==p[y].size()){
				ans[y]=d;
				++done;
				continue;
			}
			wk[p[y][lst[y]]].insert(y);
			for(int j=0;j<7;j++)if(wkd[p[y][lst[y]]][j]){
				++cur[j][p[y][lst[y]]];
			}
		}		
		if(done==k) break;
	}
	for(int i=0;i<k;i++) cout<<ans[i]+1<<" ";
	cout<<'\n';
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	slv();
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值