题目名称:大整数替换数位
题意:以字符串的形式给你一个长度为 M 的整数 N,请你计算出对这个数进行一次操作后模 9 的值为 1 的所有可能的不同操作 方式。 在一次操作中, 我们可以选择 N 的一个数位 N[i],并把它替换成另一个不同的 0 到 9 范围之内的数 B,当且仅当它们选 择的 i 或 B 不同时两种操作方式不同。
此题由CSDN用户a23333a提供
输入:第一行包含一个整数M(1<=M<=100000)。第二行包含一个大整数N。
输出:第一行输出一个整数,代表对N执行一次操作后使N模9的值为1的所有可能的不同操作方式数量。
输入示例:
4
2345
输出示例:
5
示例提示:一共有5种不同的操作方式使操作后的数模9=1。
前两种是:
i=0,B=7,即2变为7,2345->7345,7345%9=1;
i=1,B=8,即3变为8,2345->2845,2845%9=1。
题意分析:
简单来说,就是在字符串形式的整数N[i]中,选择一位数字进行替换(替换成0~9中一个与原来相异的数),使得替换以后的整数模9的结果为1。
已知能被9整除的数字:各个位上的数字之和能被9整除。
那么模9的结果为1,也就是各个位置上数字之和模9后为1。
因此主要思路就是对整数各位置上的数字求和,然后判断模9的结果。
模9的结果分为以下三种:1,0,2~8。
CASE1:
模9后结果为1:
直接满足题目要求,因此替换的数字必须刚好和原来相差9,满足条件的数字只有0和9:
用num(m)指代m出现的次数,故有num(0)+num(9)种替换方式。
CASE2:
模9后结果为0:
为了满足题目要求,需要选择一个数字进行替换,有两种满足替换的方法:
①:将某个数字替换成比原来大1的数;
②:将某个数字替换成比原来小8的数。
特别的,对于数字8而言,既可以+1,也可以-8。而其他的数字,或+1,或-8。
也就是说,8有两个可替换数,其他数字只有一个可替换数。用num(8)指代8的个数,因此共有M+num(8)种替换方式。
CASE3:
模9后结果为2~8:
假设模9后结果为s,为了满足题目要求,需要将s降至1,或升至10(对于只替换单个数字而言,只有这两种可能),设某一位置上数字为m。
①:将s降至1,即m替换以后s为1,m需要替换成比自身小s-1的数(因为此时模9后的s与1差了s-1,将某位上的m减小s-1就能满足s为1),但替换后的数字不能为负数,所以需要满足不等式m-(s-1)>=0,即m>=s-1。
②:将s升至10,即m替换以后s为10,同理,m需要替换成比自身大10-s的数,替换后的数字只能是一位数,所以满足m+(10-s)<=9,即m<=s-1。
由此可见,m取0~9的任何一位,都存在一个可替换数,特别的,当m为s-1时,有两个可替换数。综上,共有M+num(s-1)种替换方式。
其实,CASE2和CASE3在思路上可归为同一类情况,CASE2中模9的结果为0,也就是9,将CASE3中的s代入9也可以。但实际的模运算不存在9,因此为了便于操作,分为两种情况。
#include<iostream>
using namespace std;
int main() {
int M, s=0, num=0;
char N[100001];
cin>>M;
for(int i=0;i<M;i++){
cin>>N[i];
s+=N[i]-'0';//累加
s%=9;//(a+b+...)%n=(a%n+b%n+...)%n
}
//CASE1
if(s==1){
for(int i=0;i<M;i++)
if(N[i]-'0'==0||N[i]-'0'==9) num++;
}
//CASE2
else if(s==0){
for(int i=0;i<M;i++)
if(N[i]-'0'==8) num++;
num+=M;
}
//CASE3
else{
for(int i=0;i<M;i++){
if(N[i]-'0'==s-1)
num++;
}
num+=M;
}
cout<<num;
return 0;
}
“不积跬步,无以至千里;不积小流,无以成江海。” ————荀子