D.有n天,m科考试,给出每一天可以过哪一科,以及每科需要多少天复习,求最少要多少天考完,或者不可能。(n,m<=1e5)
思路:
我们可以进行二分答案,那么可以把每一科最后在那一天考计算出来,我们贪心让最早先结束的先做,最后判断一下答案就可以了。
E.题意:
有n个计算机和m个电脑设配器(只能一对一使用,且电压相同),每次我们可以对电脑设配器的电压降低一半(向上取整)
输出最多有多少个计算机能够使用以及此时最少降低的次数
对于每个电脑设配器需要降低电压的次数,哪一个电脑匹配哪一个设配器
思路:
我们可以发现,如果刚开始能够直接匹配的适配器和电脑直接匹配的话,这样方案一定是最优的,所以,
我们可以将全部设配器一起处理,处理一次的时候进行匹配,处理两次的时候进行匹配。。。
F.题目:给一个n个点m条无向边的无重边自环的连通图,让你把所有的边定向,使得从每个点出发能够到达的点数中,最小的那个尽量大。
思路:首先双连通分量里面的点一定都是能相互走到的,所以我们可以对双连通缩点,
然后形成一棵树,接下来有两种方法,
一种是二分答案,我们根据叶子节点从小往上可以确定每条边的方向
另外一种是贪心,至少有一个树上的点不能指向其它点,我们选择包含数目最多的点
PS:双连通定向写了一个下午
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+100;
typedef pair<int,int> PI;
struct Edge{
int to,next,id;
}e[N*2];
int head[N],low[N],dfn[N],belong[N],instack[N],Count[N],S[N];
int tot,top,scc,cnt,Pre[N];
vector<int>MP[N];
void init(){
tot=0;
memset(head,-1,sizeof(head));
}
void addedge(int from,int to,int id){
e[tot]=(Edge){to,head[from],id};
head[from]=tot++;
}
void Tarjan(int u,int fa){
low[u]=dfn[u]=++cnt,Pre[u]=fa;
S[++top]=u,instack[u]=1;
for(int i=head[u];i!=-1;i=e[i].next){
int v=e[i].to;
if(v==fa) continue;
if(!dfn[v]){
Tarjan(v,u);
low[u]=min(low[u],low[v]);
}
else if(instack[v])
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
scc++;
while(1){
int v=S[top--];
instack[v]=0;
belong[v]=scc;
MP[scc].push_back(v);
Count[scc]++;
if(v==u)
break;
}
}
}
vector<PI>G[N];
int n,ans_x[N],ans_y[N],vis[N],tot1;
void dfs(int x,int fa){
for(int j=0;j<MP[belong[x]].size();j++){
int u=MP[belong[x]][j];
for(int i=0;i<G[u].size();i++){
int v=G[u][i].first,id=G[u][i].second;
if(v==fa) continue;
dfs(v,u);
ans_x[id]=v,ans_y[id]=u;
}
}
}
void Dfs(int u,int pre,int Belong){
vis[u]=++tot1;
for(int i=head[u];i!=-1;i=e[i].next){
int v=e[i].to,id=e[i].id;
if(v==pre||belong[v]!=Belong) continue;
if(vis[v]!=0&&vis[v]<vis[u]) ans_x[id]=u,ans_y[id]=v;
else if(Pre[v]==u)
ans_x[id]=u,ans_y[id]=v,Dfs(v,u,Belong);
}
}
int f[N];
int find(int x){return f[x]==x ? x: f[x]=find(f[x]);}
int main(){
int m,u,v;
scanf("%d%d",&n,&m);
tot=cnt=top=scc=0;
for(int i=1;i<=n;i++) f[i]=i;
memset(head,-1,sizeof(head));
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(instack,0,sizeof(instack));
for(int i=0;i<m;i++){
scanf("%d%d",&u,&v);
addedge(u,v,i),addedge(v,u,i);
}
for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(1,-1);
int ans=0,st=1;
for(int i=1;i<=n;i++){
if(Count[belong[i]]>ans) ans=Count[belong[i]],st=i;
for(int j=head[i];j!=-1;j=e[j].next){
int v=e[j].to,id=e[j].id;
int x=find(belong[i]),y=find(belong[v]);
if(belong[i]!=belong[v]&&x!=y)
G[i].push_back((PI){v,id}),G[v].push_back((PI){i,id}),f[x]=y;
}
}
dfs(st,0),tot1=0;
printf("%d\n",ans);
for(int i=1;i<=scc;i++) Dfs(MP[i][MP[i].size()-1],0,i);
for(int i=0;i<m;i++) printf("%d %d\n",ans_x[i],ans_y[i]);
return 0;
}