• 【UR #6】懒癌


    (n)个人,每个各有一条狗。至少一条狗有病。

    人可以看到其它部分人的狗是否有病,通过有向图的形式给出,但看不出自己的狗是否有病。

    然后有若干天:

    1. 上午:每个人都去看其它狗。
    2. 下午:如果存在人能推断出自己的狗有病,那么就把狗枪毙,操作结束(如果有多个人就同时做);否则继续下一天。

    对于所有的生病情况,求:结束时间的和,被枪毙的狗数量和。

    (nle 3000)


    神仙题。

    表示自己想了半天想到了个和题解无关的复杂的大模拟,当然时间复杂度很劣……

    考虑一个人怎么知道自己的狗有病:那么他先假设自己的狗没病,据此推断出别人的行动是否合理。设(f_S)表示生病狗集合,此时结束时间。转移:枚举(iin S),从(i)的角度看:能看到的狗的状态固定,假设(i)自己没病,剩下的狗枚举状态。对于所有的这些后继状态(T),计算(max_T f_T)。于是(f_S=1+min_Smax_T f_T)

    建立一个模型来模拟DP过程:建出原来有向图的补图。一个状态相当于给这个图上一些点染黑。转移可以视作:选择一个黑点,将其变白,对于它的所有后继,决定是否将其染黑。终止状态为所有点变白。

    首先可证:在这张图上,如果存在黑点能到达环,那么无解。可以构造:钦定对后继是否染黑时,钦定全部染黑。此时显然怎么转移都无法到达终止状态。

    于是把所有能到达环的点删掉,剩下就是个DAG。

    然后可证:如果(Ssubseteq T)(f(S)le f(T))。因为此时的状态转移也是个DAG,所以可以归纳了。

    于是每次转移都直接钦定对后继全部染黑。那么转移中取(max)已经解决,只剩下取(min)

    显然可以贪心:按照拓扑序来,如果当前点为黑,那么就选择这个点进行转移。此时,结束时间就是所有黑点能够到达的点的集合大小。算出(p_i)表示图中能到达(i)的点数,第一个答案为(sum_i (2^{p_i}-1)2^{n'-p_i})

    被枪毙的狗的数量:即第一步选择转移之后,(f_T)为最小值的个数。考虑怎样转移是最优的,那么第一步转移的一定是 不存在能到达它的黑点 的点。于是第二个答案为(sum_i 2^{n'-p_i})

    用bitset优化,时间(O(frac{n^3}{omega}))


    using namespace std;
    #include <bits/stdc++.h>
    #define N 3005
    #define mo 998244353
    #define ll long long
    int n;
    ll pw[N];
    int e[N][N];
    void read(){
    	scanf("%d",&n);
    	for (int i=0;i<n;++i){
    		static char str[N];
    		scanf("%s",str);
    		for (int j=0;j<n;++j)
    			e[i][j]=str[j]-'0'^1;
    		e[i][i]=0;
    	}
    }
    int dfn[N],low[N],tim;
    int st[N],tp,ins[N];
    bool del[N];
    void tarjan(int x){
    	low[x]=dfn[x]=++tim;
    	st[++tp]=x,ins[x]=1;
    	int tmp=tp;
    	for (int y=0;y<n;++y)
    		if (e[x][y]){
    			if (!dfn[y])
    				tarjan(y),low[x]=min(low[x],low[y]);
    			else if (ins[y])
    				low[x]=min(low[x],dfn[y]);
    			del[x]|=del[y];
    		}
    	if (low[x]==dfn[x]){
    		bool bz=(tp-tmp+1>1);
    		for (int i=tmp;i<=tp;++i) bz|=del[st[i]],ins[st[i]]=0;
    		if (bz)
    			for (int i=tmp;i<=tp;++i) del[st[i]]=1;
    		tp=tmp-1;
    	}
    }
    int m,p[N];
    int deg[N];
    queue<int> q;
    bitset<N> b[N];
    void BFS(){
    	for (int i=0;i<n;++i)
    		if (!del[i]){
    			++m;
    			for (int j=0;j<n;++j)
    				if (!del[j] && e[i][j])
    					deg[j]++;
    		}
    	for (int i=0;i<n;++i)
    		if (!del[i]){
    			b[i][i]=1;
    			if (!deg[i])
    				q.push(i);
    		}
    	while (!q.empty()){
    		int x=q.front();
    		q.pop();
    		for (int y=0;y<n;++y)	
    			if (!del[y] && e[x][y]){
    				b[y]|=b[x];
    				if (!--deg[y])
    					q.push(y);
    			}
    	}
    	for (int i=0;i<n;++i)
    		p[i]=b[i].count();
    }
    int main(){
    	read();
    	for (int i=0;i<n;++i)
    		if (!dfn[i])
    			tarjan(i);
    	BFS();
    	pw[0]=1;
    	for (int i=1;i<=n;++i)
    		pw[i]=pw[i-1]*2%mo;
    	ll ans1=0,ans2=0;
    	for (int i=0;i<n;++i)
    		if (!del[i]){
    			(ans1+=(pw[p[i]]-1)*pw[m-p[i]])%=mo;
    			(ans2+=pw[m-p[i]])%=mo;
    		}
    	printf("%lld %lld
    ",ans1,ans2);
    	return 0;
    }
    
  • 相关阅读:
    多测师杭州拱墅校区肖sir_高级金牌讲师_项目讲解讲解和注意方式
    多测师杭州拱墅校区肖sir_高级金牌讲师_redis(参考)
    多测师杭州拱墅校区肖sir_高级金牌讲师_测试环境搭建问题
    【ArangoDb踩坑】新增Edge类型数据,from和to为document的_id
    firmware file rtl_bt/rtl8761b_fw.bin not found
    非递归前序遍历
    ELK & EFK
    边缘计算 controller提供的功能
    oran code go through
    hugepages configure
  • 原文地址:https://www.cnblogs.com/jz-597/p/14870514.html
Copyright © 2020-2023  润新知