原题链接
P1037
题目类型:
普
及
+
/
提
高
{\color{green}{普及+/提高}}
普及+/提高
AC记录:Accepted
题目大意
给定一个数字 n n n和 k k k个规则,规则的内容是可以让一个一位数变成另一个一位数,求在这些规则下,可能产生多少个数(包括自己)。
输入格式
第一行两个整数
n
,
k
n,k
n,k。
接下来
k
k
k行,每行两个整数
x
i
,
y
i
x_i,y_i
xi,yi,代表可以从
x
i
x_i
xi转换成
y
i
y_i
yi。
输出格式
输出能生成的数字个数。
S
a
m
p
l
e
\mathbf{Sample}
Sample
I
n
p
u
t
\mathbf{Input}
Input
234 2
2 5
3 6
S a m p l e \mathbf{Sample} Sample O u t p u t \mathbf{Output} Output
4
H
i
n
t
&
E
x
p
l
a
i
n
\mathbf{Hint\&Explain}
Hint&Explain
在样例中,有以下
2
2
2个规则:
2
→
5
,
3
→
6
2\to 5,3\to 6
2→5,3→6。
则
234
234
234可以变成
234
,
534
,
264
,
564
234,534,264,564
234,534,264,564,总共
4
4
4种,答案为
4
4
4。
数据范围
对于 100 % 100\% 100%的数据, 1 ≤ n ≤ 1 0 30 , 1 ≤ k ≤ 15 1≤n≤10^{30},1≤k≤15 1≤n≤1030,1≤k≤15。
解题思路
我第一次看到这道题时,就想着可以把可能变化到的数字个数乘起来,得到答案。
实际上,这种思路并没有错,但是难点在于:如何找出一个数字可能变化到的数字?
这里就要涉及到一个判断图中的两点是否连通的思路,这里用的是类似
F
l
o
y
e
d
Floyed
Floyed的算法。
你可以想,如果你像
F
l
o
y
e
d
Floyed
Floyed一样,枚举一个中间点,判断他可不可通的话,这里就要用一个式子:设
f
α
,
β
f_{\alpha,\beta}
fα,β为
0
0
0则
α
,
β
\alpha,\beta
α,β两点没有连边,为
1
1
1则
α
,
β
\alpha,\beta
α,β两点有连边,
k
k
k为中间点。则f[i][j] = f[i][j] || ( f[i][k] && f[k][j] )
。f[i][k] && f[k][j]
是判断
i
→
k
i\to k
i→k和
k
→
j
k\to j
k→j是否都相通,而前面用一个||
都很清楚,只要可行,就可以设为true
。
这样一来,数字是否相通的问题就解决了。
但是,有个问题,数字乘起来爆unsigned long long
怎么办?开高精度。
或者根据我们机房的某位大佬
U
n
n
a
m
e
d
_
C
u
b
e
\mathrm{\color{grey}U\color{red}{nnamed\_Cube}}
Unnamed_Cube所说,本题可以用__int128_t
水过。
最后,祝大家早日
上代码
#include<bits/stdc++.h>
using namespace std;
string s;
bool road[20][20];
int can_be[20];
int mul[10010];
int n;
int main()
{
cin>>s>>n;
for(int i=0; i<=9; i++)
road[i][i]=true;
for(int i=1; i<=n; i++)
{
int x,y;
cin>>x>>y;
road[x][y]=true;
}
for(int k=0; k<=9; k++)
for(int i=0; i<=9; i++)
for(int j=0; j<=9; j++)
road[i][j]=road[i][j]||(road[i][k]&&road[k][j]);
for(int i=0; i<=9; i++)
for(int j=0; j<=9; j++)
if(road[i][j])
can_be[i]++;
mul[10000]=1;
int up=0;
for(int i=0; i<s.size(); i++)
{
int num=can_be[s[i]-'0'];
for(int j=10000; j>=1; j--)
{
mul[j]=mul[j]*num+up;
up=mul[j]/10;
mul[j]%=10;
}
}
int pos=1;
while(pos<10000&&mul[pos]==0)
pos++;
for(; pos<=10000; pos++)
cout<<mul[pos];
cout<<endl;
return 0;
}
完美切题 ∼ \sim ∼