码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 5278 YJC plays automaton

时间:2015-07-06 12:18:51      阅读:175      评论:0      收藏:0      [点我收藏+]

标签:algorithm   搜索   

YJC plays automaton

 
 Accepts: 1
 
 Submissions: 14
 Time Limit: 12000/6000 MS (Java/Others)
 
 Memory Limit: 524288/262144 K (Java/Others)
问题描述
YJC是个小火车老司机,所以他是袜子坊烧饼栏目举办的“吃的更圆”竞赛金牌获得者,他去吃特色菜时看到一个n+1个状态的自动机,编号为0n,其中0号点表示NULL,他非常好奇于是开始了研究:
他选取了一个初始状态集合S,发现其有如下有趣性质:
存在一个字符串str,使得S中的每一个元素在自动机上运行了str之后,得到的结束状态集合包含NULL和至少一个NULL以外的状态,即S中运行str后到达NULL的状态数目在[1,|S|?1]中。
满足这个性质的集合叫做YJC集,注意YJC集不能包含NULL。
他想知道有多少个YJC集。

关于自动机在本题中你可以这样理解:
自动机有n+1个状态,编号0n,其中0NULL状态,设字符集大小为m。
有转移函数δ(i,j)(0in,1jm),满足0δ(i,j)nδ(0,j)=0
一个状态t在自动机上运行字符串str可以参考以下程序
for  i=0..str.length?1
    tδ(t,str[i])
你还可以查看
https://zh.wikipedia.org/wiki/自動機理論
输入描述
第一行两个正整数n,m(1n888,1m8),表示自动机大小和字符集大小。
nmδ(i,j)ij0NULL
NULLNULL

最终测试时,输入文件不超过11000行,共31组。

由于测试时是总时限,若你的程序最坏情况下可以在0.5s内通过1组极限数据(CPU 3.0 GHz),一般可以通过systemtest。
输出描述
一行一个整数,表示YJC集的个数。
答案对998244353(7×17×223+1)取模。
输入样例
3 2
3 0
3 0
0 3
输出样例
3
Hint
可能的YJC集有:{1,3},{2,3},{1,2,3}
状态1,2是等价的,显然1,2不是YJC集
思路:建立反向图,先考虑二元组,使用bfs把目的状态能到达的二元组记下来。最后计算答案,好难表述。


/*hdu 5278 YJC plays automaton
  思路:
  建立反向图,先考虑二元组,使用bfs把目的状态能到达的二元组记下来。
  最后计算答案,好难表述。
 */
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
#define PII pair<int,int>
#define LL __int64
#define MP make_pair
#define PB push_back
#define X first
#define Y second
const int MOD=998244353;
const int N=1005;
const int M=10;
int tran[N][M];
LL two[N];
void predo(){
	two[0]=1;
	for(int i=1;i<N;++i)
		two[i]=two[i-1]*2%MOD;
}

vector<PII> e[N][N];
PII que[N*N];
int front,tail;

int fa[N],num[N];
void init_bcj(){
	for(int i=0;i<N;++i){
		fa[i]=i;
		num[i]=1;
	}
}
int getFa(int x){
	if(x!=fa[x]) return fa[x]=getFa(fa[x]);
	return x;
}
void bin(int x,int y){
	int fx=getFa(x);
	int fy=getFa(y);
	if(fx==fy) return ;
	fa[fy]=fx;
	num[fx]+=num[fy];
	num[fy]=0;
}


int mark=0;
int used[N][N];
void gao(int n,int m){
	++mark;
	for(int i=0;i<=n;++i)
		for(int j=0;j<=n;++j)
			e[i][j].clear();

	for(int x1=0;x1<=n;++x1){
		for(int y1=x1+1;y1<=n;++y1){
			for(int i=0;i<m;++i){
				int x2=tran[x1][i];
				int y2=tran[y1][i];
				if(x2>y2) swap(x2,y2);
				e[x2][y2].PB(MP(x1,y1));
			}
		}
	}
	front=tail=0;
	for(int i=1;i<=n;++i){
		que[tail++]=MP(0,i);
		used[0][i]=mark;
	}
	while(front<tail){
		PII now=que[front++];
		for(int i=0;i<e[now.X][now.Y].size();++i){
			int tmpx=e[now.X][now.Y][i].X;
			int tmpy=e[now.X][now.Y][i].Y;
			if(used[tmpx][tmpy]==mark) continue;
			que[tail++]=MP(tmpx,tmpy);
			used[tmpx][tmpy]=mark;
		}
	}
	
	init_bcj();
	for(int i=1;i<=n;++i){
		for(int j=i+1;j<=n;++j){
			if(used[i][j]!=mark) bin(i,j);
		}
	}

	LL ans=(two[n]-1+MOD)%MOD;
	for(int i=1;i<=n;++i){
		if(num[i]){
			//cout<<i<<' '<<num[i]<<endl;
			ans=(ans-(two[num[i]]-1)+MOD)%MOD;
		}
	}
	cout<<ans<<endl;

}
int main(){
	predo();
	int n,m;
	while(scanf("%d%d",&n,&m)!=EOF){
		for(int i=1;i<=n;++i)
			for(int j=0;j<m;++j)
				scanf("%d",&tran[i][j]);
		gao(n,m);
	}
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

hdu 5278 YJC plays automaton

标签:algorithm   搜索   

原文地址:http://blog.csdn.net/whai362/article/details/46771873

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!