Andrew Stankevich Contest 9(Codeforces)
题意:
有一个n个点,m条边的有向图,现在有布置k个点作为警察局,要求可以通过警察局从每个城市的道路到达某个城市,从警察局到某个城市的道路可以到达每个城市。
求出布置k个警察局可能数
首先看这个数据范围就要高精度 o(╥﹏╥)o
不爽 (•́へ•́╬)
先不提高精的事。
这题看着其实挺裸的。
一看又是 SCC+DP S C C + D P 的模型 (SCC不会的请看裸题(Checkposts))
思考DP方程
dp[i][j] d p [ i ] [ j ] 表示前个顶点安排j个警察局的方案数
对于没有入度或出度的点,我们单独考虑,因为这些点都必须放 Police P o l i c e Station S t a t i o n
没有入度或出度用SCC解决
dp[i][j]=∑k<jk=0dp[i−1][k]∗c[x][j−k] d p [ i ] [ j ] = ∑ k = 0 k < j d p [ i − 1 ] [ k ] ∗ c [ x ] [ j − k ]
代码细看,这个题是不错的。
对于高精度不熟悉的同学,建议用 Struct S t r u c t 定义 Biginteger B i g i n t e g e r 类,之后打一下模板
注意高精度请勿输出前导零
我也打了一天才AC
Code:
include <bits/stdc++.h>
using namespace std ;
const int N = 110;
//高精模板开始
struct bign{
int len,s[N];
bign(){ memset(s,0,sizeof(s));len=1;}
bign(int num){*this=num;}
bign(char *num){*this=num;}
bign operator =(int num){
char c[N];
sprintf(c,"%d",num);
*this=c;
return *this;
}
bign operator =(const char *num){
len=strlen(num);
for (int i=0;i<len;i++) s[i]=num[len-1-i]-'0';
return *this;
}
string str(){
string res="";
for (int i=0;i<len;i++) res=(char)(s[i]+'0')+res;
return res;
}
void clean(){
while (len>1&&!s[len-1]) len--;
}
bign operator +(const bign &b){
bign c;
c.len=0;
for (int i=0,g=0;g||i<len||i<b.len;i++){
int x=g;
if (i<len) x+=s[i];
if (i<b.len) x+=b.s[i];
c.s[c.len++]=x%10;
g=x/10;
}
return c;
}
bign operator -(const bign &b){
bign c;
c.len=0;
int x;
for (int i=0,g=0;i<len;i++){
x=s[i]-g;
if (i<b.len) x-=b.s[i];
if (x>=0) g=0;
else{
x+=10;
g=1;
};
c.s[c.len++]=x;
}
c.clean();
return c;
}
bign operator *(const bign &b){
bign c;
c.len=len+b.len;
for (int i=0;i<len;i++) for (int j=0;j<b.len;j++) c.s[i+j]+=s[i]*b.s[j];
for (int i=0;i<c.len-1;i++) { c.s[i+1]+=c.s[i]/10; c.s[i]%=10; }
c.clean();
return c;
}
bool operator <(const bign &b){
if (len!=b.len) return len<b.len;
for (int i=len-1;i>=0;i--)
if (s[i]!=b.s[i]) return s[i]<b.s[i];
return false;
}
bign operator +=(const bign &b){
*this=*this+b;
return *this;
}
bign operator -=(const bign &b){
*this=*this-b;
return *this;
}
};
istream& operator >>(istream &in,bign &x){
string s;
in>>s;
x=s.c_str();
return in;
}
ostream& operator <<(ostream &out,bign &x){
out<<x.str();
return out;
}
//高精大模板就此结束
vector <int> G[N],nod,hd ;//nod存储没有d的点
stack <int> S ;
int link[N],din[N],dout[N],dfn[N],low[N],sd[N] ;
//link[i]表示SCC i有多少个点,din和dout分别表示i的入度和出度
//dfn和low是Trajan里要干的
//sd表示缩点
bool vis[N] ;
bign dp[N][N],c[N][N] ;
int n,m,K,cnt,tot ;
void tarjan(int now){ //tarjan ---> scc
dfn[now]=low[now]=++tot ;
vis[now]=true;S.push(now) ;
for (int i=0;i<G[now].size();i++){
int to=G[now][i] ;
if (!dfn[to]){
tarjan(to) ;
low[now]=min(low[now],low[to]) ;
}
else if (vis[to]) low[now]=min(low[now],dfn[to]) ;
}
if (dfn[now]==low[now]){
sd[now]=++cnt ;
link[cnt]++ ;
vis[now]=false ;
while(S.top()!=now){
sd[S.top()]=cnt;
link[cnt]++ ;
vis[S.top()]=false ;
S.pop() ;
}
S.pop() ;
}
}
void init_c(){ //预处理出C数组
for(int i=0;i<N;i++){
c[i][0]=c[i][i]=1 ;
for (int j=1;j<i;j++) c[i][j]=c[i-1][j-1]+c[i-1][j] ;
}
}
void init(){
tot=cnt=0 ;
memset(dfn,0,sizeof(dfn)) ;
memset(low,0,sizeof(low)) ;
memset(vis,0,sizeof(vis)) ;
memset(sd,0,sizeof(sd)) ;
memset(link,0,sizeof(link)) ;
memset(din,0,sizeof(din)) ;
memset(dout,0,sizeof(dout)) ;
memset(dp,0,sizeof(dp)) ;
nod.clear() ;
hd.clear() ;
for (int i=0;i<=N;i++) G[i].clear() ;
while (!S.empty()) S.pop() ;
}
int main(){
ios::sync_with_stdio(false) ;
init_c() ;
while(~scanf("%d%d%d",&n,&m,&K)){
init() ;
for (int i=1;i<=m;i++){
int x,y ;
scanf("%d%d",&x,&y) ;
G[x].push_back(y) ;
}
for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i) ;
dp[0][0]=1 ;
for (int i=1;i<=n;i++){
for (int j=0;j<G[i].size();j++){
int v=G[i][j] ;
if (sd[i]==sd[v]) continue ;
din[sd[v]]++;
dout[sd[i]]++ ;
}
}
for (int i=1;i<=cnt;i++)
if (!din[i] || !dout[i]) nod.push_back(i) ;
else hd.push_back(i) ;
for (int i=1;i<=nod.size();i++)
for (int j=1;j<=K;j++)
for (int k=j-1;k>=0 && j-k<=link[nod[i-1]];k--)
dp[i][j]+=dp[i-1][k]*c[link[nod[i-1]]][j-k] ;
for (int i=nod.size()+1,t=0;i<=cnt;i++,t++)
for (int j=nod.size();j<=K;j++)
for (int k=nod.size();k<=j;k++)
dp[i][j]+=dp[i-1][k]*c[link[hd[t]]][j-k] ;
cout<<dp[cnt][K]<<endl<<endl ;
}
}