P1037 [NOIP2002 普及组] 产生数

题目描述

给出一个整数 �n 和 �k 个变换规则。

规则:

  • 一位数可变换成另一个一位数。
  • 规则的右部不能为零。

例如:�=234,�=2n=234,k=2。有以下两个规则:

  • 2⟶52⟶5。
  • 3⟶63⟶6。

上面的整数 234234 经过变换后可能产生出的整数为(包括原数):

  • 234234。
  • 534534。
  • 264264。
  • 564564。

共 44 种不同的产生数。

现在给出一个整数 �n 和 �k 个规则。求出经过任意次的变换(00 次或多次),能产生出多少个不同整数。

仅要求输出个数。

输入格式

第一行两个整数 �,�n,k,含义如题面所示。

接下来 �k 行,每行两个整数 ��,��xi​,yi​,表示每条规则。

输出格式

共一行,输出能生成的数字个数。

输入输出样例

输入 #1复制

234 2
2 5
3 6

输出 #1复制

4

说明/提示

对于 100%100% 数据,满足 �<1030n<1030,�≤15k≤15。

【题目来源】

NOIP 2002 普及组第三题

正经深搜解法

好的,我们先贴一个题面

P1037 Make Numbers (假装大家已经看完题面了

  • 思路一: 如果考虑如果一个数一个数地记录

    我觉得不行~

证明:显然易见得平凡读者自证不难。

我们注意到

给出一个整数 �(�<1030)n(n<1030) 和 �k 个变换规则 �≤15k≤15。

不好意思,

QAQ好像……有点大,溜了溜了。

  • 思路二: 那么我们考虑一位一位地转化然后再借助乘法原理乘起来

    哦,你可真是个天才。 于是就有了以下代码:

#include<iostream>
using namespace std;
string qwq;
int s[33],num[33],k,nxt[33][16],qaq;
bool vis[10];
long long ans = 1;
void dfs(int x,int y)
//x指上一个到达的数,y指现在的
{
//机房神仙说传一个参数就可以,但宝宝不会QAQ
	if(vis[y])return;//对于环状循环的处理
	vis[x] = 1;//记忆化
	qaq++;
	for(int i = 1;i <= num[y];i++)
		dfs(y,nxt[y][i]);
	vis[x] = 0;//归零
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(NULL),cout.tie(NULL);
   	//看不懂可忽略,就是取消cin&cout前后摇
	cin>>qwq>>k;
	int len = qwq.size();
	for(int i = 0;i < len;i++)
		s[i + 1] = qwq[i] - '0';
	for(int i = 1;i <= k;i++)
	{
		int x,y;
		cin>>x>>y;
		nxt[x][++num[x]] = y;
	}
	for(int i = 1;i <= len;i++)
	{
		qaq = 1;
		for(int j = 1;j <= num[s[i]];j++)
			dfs(s[i],nxt[s[i]][j]);
		ans *= qaq;
	}
	cout<<ans;
}

恭喜你,八十分(别打了

  • 于是我们又一次注意到了:

给出一个整数 �(�<1030)n(n<1030) 和 �k 个变换规则 �≤15k≤15。

完了,不会写高精乘高精,怎么办 来山东蓝翔挖掘机学校

那就高精乘低精呗hhh

AC Code:

#include<bits/stdc++.h>
using namespace std;
string qwq;
int s[33],num[33],k,nxt[33][16],qaq;
//万能头选手注意莫用next当数组名
bool vis[10];
int ans[33];
void dfs(int x,int y)
{
	vis[x] = 1;
	if(vis[y])return;
	qaq++;
	for(int i = 1;i <= num[y];i++)
		dfs(y,nxt[y][i]);
}

void mul(){
	int jw = 0;
	for(int i = 30;i;i--)
	{
		ans[i] = ans[i] * qaq + jw;
		jw = ans[i] / 10;
		ans[i] %= 10;
	}
}//根据原理手写一个就好了

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(NULL),cout.tie(NULL);
	ans[30] = 1;
	cin>>qwq>>k;
	int len = qwq.size();
	for(int i = 0;i < len;i++)
		s[i + 1] = qwq[i] - '0';
	for(int i = 1;i <= k;i++)
	{
		int x,y;
		cin>>x>>y;
		nxt[x][++num[x]] = y;
	}
	for(int i = 1;i <= len;i++)
	{
		qaq = 1;
		for(int j = 1;j <= num[s[i]];j++)
			dfs(s[i],nxt[s[i]][j]);
		memset(vis,0,sizeof(vis));
		mul();
	}
	int l = 0;
	for(;ans[l]==0;l++);//处理前导零
	for(int i = l;i <= 30;i++)
		cout<<ans[i];
	return 0;
}

control,简写为Ctrl,扩写为:

唱,跳,rap,篮球.

您还敢Ctrl+C吗

欢迎批评指正

码字不易,良心小编,留赞再走。QAQ

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值