输入包括两行:
第一行为盒子上的数值k,模糊的数位用X表示,长度小于18(可能有多个模糊的数位)
第二行为小朋友的人数n
输出k可能的数值种数,保证至少为1
9999999999999X 3
4
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNext()) {
String s = in.nextLine();
String s2 = in.nextLine();
int n = Integer.parseInt(s2);
long d[] = new long[n];//n children
boolean dLoaded = false;
long base = 1;
long sum = 0;
for (int j = 0; j < s.length(); j++) {
base *= 10;
}
//遍历每一位数字。
for (int i = 0; i < s.length(); i++) {
//对base除以10,为下一位求余做准备。
base /= 10;
if (s.charAt(i) == 'X') {
if (!dLoaded) {
//如果记录余数的数组d还没初始化过,就先把这次的计算作为初始化的值。
long[] temp = new long[n];
//统计余数的数组。长度为n,下标是0~n-1,表示 对应可以得到对应余数的个数。
for (int j = 0; j <= 9; j++) {
temp[(int) ((j * base) % n)]++;
}
//temp数组复制到d数组上。这里idea优化成如下方法,效率更高。d数组便初始化过了。跳过后面部分
System.arraycopy(temp, 0, d, 0, n);
dLoaded = true;
continue;
}
//如果初始化了d数组,则在新发现X时,需要把新的余数统计结果和原来的统计结果d进行汇总
int[] mod = new int[10];
//因为x有10种可能,所以最多产生10个余数,而如果采用new int[n]来统计的话,n可能远大于10,所以效率会差很多。mod记录了每个可能的数字所产生的余数。
for (int j = 0; j <= 9; j++) {
mod[j] = (int) ((j * base) % n);
}
//将新的统计结果mod和原来的统计结果d进行融合。原理如下:newd的下标对应产生的余数,比如newd[2]代表余数为2的所有可能性总数。于是对于newd[m],其可能性总数便来自于 sum{d[m-mod[k]]}(仔细想一下,mod[k]是这次产生的新余数,m是要统计的目标余数),+n和%n是为了防止负数情况。
long[] newd = new long[n];
for (int m = 0; m < n; m++) {
for (int k = 0; k <= 9; k++) {
newd[m] += d[(n + m - mod[k]) % n];
}
}
System.arraycopy(newd, 0, d, 0, n);
} else {
//如果不是x,就按最开始处讲的原理直接求余并累加进去即可。
long a = (s.charAt(i) - '0') * base;
sum = (sum + a) % n;
}
}
//常数位累加后的余数是sum,而我们要能整除的所有可能性,也就是余数为0的所有可能性,所以取d数组中的n-sum对应的可能性即可。为何%n?比如n=7,sum=0,n-sum=7,d[7]显然越界。实际上此时应该去访问d[7%7]=d[0]
System.out.println(d[(int) ((n - sum) % n)]);
}
}
}
package go.jacob.day918; import java.util.Scanner; /** * [编程题]分饼干 * * @author Jacob * Long表示范围为-9223372036854775808到9223372036854775807(19位) */ public class Demo1 { /* * 动态规划求解 * 用暴力解***超时 */ public static void main(String[] args) { Scanner sc = new Scanner(System.in); String s = sc.next(); int len = s.length(); int n = sc.nextInt(); // dp[i][j]表示前i位(高位开始)余数为j的个数 long[][] dp = new long[len + 1][n]; dp[0][0] = 1;// 初始化 for (int i = 0; i < len; i++) { for (int j = 0; j < n; j++) { // 如果当前位为X,用0-9带入 if (s.charAt(i) == 'X') { for (int k = 0; k <= 9; k++) { dp[i + 1][(j * 10 + k) % n] += dp[i][j]; } } else {// 如果当前位上的数字为不为X,用具体值带入 dp[i + 1][(j * 10 + s.charAt(i) - '0') % n] += dp[i][j]; } } } System.out.println(dp[len][0]); sc.close(); } }
#include<iostream> #include<string> #include<vector> using namespace std; int main(){ string s; int n; while (cin >> s >> n){ int len = s.length(); vector<vector<long long int>> dp(len + 1, vector<long long int>(n, 0)); dp[0][0] = 1; for (int i = 1; i <= s.length(); i++){ for (int j = 0; j < n; j++){ if (s[i - 1] == 'X'){ for (int k = 0; k < 10; k++){ int newJ = (j * 10 + k) % n; dp[i][newJ] += dp[i - 1][j]; } } else{ int newJ = (j * 10 + (s[i - 1] - '0')) % n; dp[i][newJ] += dp[i - 1][j]; } } } cout << dp[len][0] << endl; } return 0; }
import java.util.*; public class Main{ public static void main(String[] args) { Scanner in = new Scanner(System.in); while(in.hasNext()){ String s = in.nextLine(); int n = in.nextInt(); int len = s.length(); long long[][] dp = new long long[len + 1][n]; dp[0][0] = 1; for(int i = 1; i <= len; i++){ for(int j = 0; j < n; j++){ if(s.charAt(i - 1) == 'X'){ for(int k = 0; k <= 9; k++){ int newJ = (j * 10 + k) % n; dp[i][newJ] += dp[i - 1][j]; } } else{ int newJ = (j * 10 + (s.charAt(i - 1) - '0')) % n; dp[i][newJ] += dp[i - 1][j]; } } } System.out.println(dp[len][0]); } in.close(); } }
# -*- coding: utf-8 -*- # 输入k,n k = raw_input() n = int(raw_input()) remainders = [1] + [0] * (n - 1) for i, s in enumerate(k): temp = [0] * n if s != 'X': s = int(s) for j in range(n): temp[(j*10+s) % n] += remainders[j] else: for s in range(10): for j in range(n): temp[(j*10+s) % n] += remainders[j] remainders = temp print remainders[0]
/*dp[i][j]表示长度为i的数 除以小朋友的人数之后得到的余数为j的个数dp[i][newJ] = dp[i-1][j], s[i] != 'X', newJ = (j*10+s[i]-'0')%n;dp[i-1][j], s[i] == 'X', newJ = (j*10+k)%n, k=0~9*/import java.util.*;public class Main {public static void main(String[] args) {// TODO Auto-generated method stubScanner scan = new Scanner(System.in);while(scan.hasNext()){String s= scan.nextLine();int n = scan.nextInt();long[][] dp = new long[s.length()+1][n];dp[0][0] = 1;for(int i=1; i<=s.length(); i++)for(int j=0; j<n; j++){if(s.charAt(i-1) == 'X'){for(int k=0; k<=9; k++){int newJ = (j*10+k)%n;dp[i][newJ] += dp[i-1][j];}} else{int newJ = (j*10+s.charAt(i-1)-'0')%n;dp[i][newJ] += dp[i-1][j];}}System.out.println(dp[s.length()][0]);}}}
分析:枚举每个位置的数字,然后记录满足要求的答案数就可。#include <bits/stdc++.h>using namespace std;longlongn1[10001], n2[10001];intmain(){string s;intn;cin >> s >> n;longlongret = 0;n1[0] = 1;for(inti = 0; i < s.size(); i++){memset(n2, 0, sizeof(n2));for(intj = 0; j < n; j++){for(intk = 0; k < 10; k++){if(isdigit(s[i]) && s[i] - '0'!= k) continue;n2[ ( ( j * 10) + k ) % n] += n1[j];}}memcpy(n1,n2,sizeof(n1));}cout << n1[0] << endl;}
#include<iostream> #include<cstring> using namespace std; #define MAXN 100000 void transform1(long long mod[],int n){ long long tmpMod[MAXN]={0}; for(int i=0;i<n;i++){ for(int j=0;j<10;j++){ tmpMod[(i*10+j)%n]+=mod[i]; } } memcpy(mod,tmpMod,sizeof tmpMod); } void transform2(long long mod[],int k,int n){ long long tmpMod[MAXN]={0}; for(int i=0;i<n;i++){ tmpMod[(i*10+k)%n]+=mod[i]; } memcpy(mod,tmpMod,sizeof tmpMod); } int main(){ long long mod[MAXN]={0}; string s; int n; cin>>s>>n; mod[0]=1; for(int i=0;i<s.length();i++){ if(s[i]=='X'){ transform1(mod,n); }else{ transform2(mod,s[i]-'0',n); } } cout<<mod[0]<<endl; }
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); String str = sc.next(); int n = sc.nextInt(); long[][] dp = new long[str.length()+1][]; //不用long的话通过率只能为90% for(int i = 0;i<=str.length();i++){ dp[i] = new long[n]; } dp[0][0] = 1; for(int i = 1;i<=str.length();i++){ char c = str.charAt(i-1); for(int j = 0;j<n;j++){ for(int k = 0;k<10;k++){ if(c=='X'||c=='0'+k){ dp[i][(j*10+k)%n]+=dp[i-1][j]; } } } } System.out.println(dp[str.length()][0]); } } //以上发现第i行的值只会访问到第i-1行的值,所以实际只需要两个数组即可,优化空间之后的代码: import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); String str = sc.next(); int n = sc.nextInt(); long[] dp = new long[n]; dp[0] = 1; for(int i = 1;i<=str.length();i++){ char c = str.charAt(i-1); long[] tmp = new long[n]; for(int j = 0;j<n;j++){ for(int k = 0;k<10;k++){ if(c=='X'||c=='0'+k){ tmp[(j*10+k)%n]+=dp[j]; } } } dp = tmp; } System.out.println(dp[0]); } }
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();//模糊数值
int n = sc.nextInt();//小朋友个数
long[][] dp = new long[s.length() + 1][n];//dp[i][j]表示前i个字符串表示的整数除n后余数为j的总数。
dp[0][0] = 1;
for(int i = 1; i <= s.length(); i++) {
for(int j = 0; j < n; j++) {
char c = s.charAt(i - 1);
if(c == 'X') {
//当前字符为X的时候,和下面的分析同理。只是当前位置的数字不是固定的,可能是0-9中的任何一个。
for(int k = 0; k <= 9 ;k++) {
dp[i][(10 * j + k) % n] += dp[i - 1][j];
}
}
else {
//前i-1字符串组成的整数 除n得的余数为j的情况有dp[i - 1][j]种,余数只能在0到n-1的范围
//假设前i-1字符串组成的数是125,n=4,余数为125 % 4 = 1,
//所以dp[3][0]=0,dp[3][1]=1,dp[3][2]=0,dp[3][3] = 0
//假设第i个字符为6,所以新的数变成1256,1256 % n就相当于(125 * 10 + 6) % n
//相当于[(124 + 1)*10 + 6] % n,因为前i-1个组成的数中125 % n = 1,所以(125 - 1) * 10是能除尽n的
//所以就相当于[(1 * 10) + 6] % n ,而 1 就是前i-1个组成的数除n得到的余数,所以前i-1个组成的数除n有多少个余
//数为1的情况,那么前i个组成的数就有多少种余数为[(1*10) + 6] % n 的情况。
//for(int j = 0; j < n; j++) 此for循环中的j代表前i-1个组成的数除n得到的余数,余数从0到n-1
dp[i][(10 * j + c - '0') % n] += dp[i - 1][j];
}
}
}
System.out.println(dp[s.length()][0]);
}
}
import java.util.Scanner;
/*
* 参考大神的解题思路:
*
* https://www.nowcoder.com/questionTerminal/44d0ee89b51b4725b403d1df2381d2b2
* 显然此题直接暴力会超时,10^18中可能情况,考虑使用动态规划
* dp[i][j]表示前i个字符串对应整数mod n之后余数为j的情况数
* 如果当下字符为X,则可以遍历0-9重新进行计算;
* 否则可以具体计算出dp值
* */
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
String line = scanner.next();
int n = scanner.nextInt();
int len = line.length();
long[][] dp = new long[len + 1][n];
dp[0][0] = 1;
for (int i = 1; i <= len; i++) {
for (int j = 0; j < n; j++) {
char c = line.charAt(i - 1);
if (c == 'X') {
// 0-9进行遍历
for (int k = 0; k < 10; k++) {
dp[i][(j * 10 + k) % n] += dp[i - 1][j];
}
} else {
// 直接计算
dp[i][(j * 10 + c - '0') % n] += dp[i - 1][j];
}
}
}
System.out.println(dp[len][0]);
}
}
}
#include <bits/stdc++.h> using namespace std; using ulli = unsigned long long int; ulli doit(vector<ulli>& vec, ulli total, ulli n) { vector<vector<ulli>> dp = vector<vector<ulli>>(vec.size() + 1, vector<ulli>(n, 0)); // dp[i][j] means how many kinds of combination when check i , remain is j if (vec.empty()) {return total % n == 0;} dp[0][total] = 1; for (int i = 0; i < dp.size() - 1; i++) { for (ulli j = 0; j < n; j++) { if (dp[i][j] == 0) { continue;} for (int k = 0; k < 10; k++) { ulli newremain = (j + (k * vec[i])) % n; dp[i + 1][newremain] += dp[i][j]; } } } return dp[vec.size()][0]; } int main() { string oneline; //while (getline(cin, oneline)) { cin >> oneline; ulli n; cin >> n; ulli base = 0; ulli digit = 1; vector<ulli> mode_remain_of_digits_of_x; for (int i = oneline.size() - 1; i >= 0; i--) { if (oneline[i] == 'X') { mode_remain_of_digits_of_x.push_back(digit % n); } else { base += digit * (oneline[i] - '0'); } digit *= 10; } ulli total = base % n; cout << doit(mode_remain_of_digits_of_x, total, n) << endl; //} }
#include <iostream> #include <cstring> #include <cmath> #include <algorithm> #include <cstdio> using namespace std; int main() { string s; cin>>s; int n; cin>>n; //d[i][j]表示前i位%n的结果 long long d[20][10000]; memset(d,0,sizeof(d)); d[0][0]=1; int len=s.size(); for(int i=1;i<=len;i++) for(int j=0; j<n;j++) if(s[i-1]=='X') { for(int k=0;k<=9;k++) { int newj=(j*10+k)%n; d[i][newj]+=d[i-1][j]; } } else { int newj=(j*10+(s[i-1]-'0'))%n; d[i][newj]+=d[i-1][j]; } cout<<d[len][0]<<endl; return 0; }
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (sc.hasNext()) { String s = sc.nextLine(); int n = Integer.parseInt(sc.nextLine()); long[][] dp = new long[s.length()+1][n]; dp[0][0] = 1; for (int i = 1; i <= s.length(); i++) { if(s.charAt(i-1) == 'X') { for (int k = 0; k < 10; k++) { int ret = (int)((Math.pow(10, s.length() - i) * k) % n); for (int j = 0; j < n; j++) { dp[i][j] += dp[i-1][(j + n - ret) % n]; } } } else { int ret = (int) ((Math.pow(10, s.length() - i) * (s.charAt(i-1) - '0')) % n); for (int j = 0; j < n; j++) { dp[i][j] += dp[i-1][(j + n - ret) % n]; } } } System.out.println(dp[s.length()][0]); } } }
#include <iostream> #include <string> using namespace std; void findans(string &s,int &countx,int n,int t){ if(t==s.length()){ int num=atoi(s.c_str()); if (num%n == 0) countx++; return; } if(s[t]=='X'){ for(int i=0;i<=9;i++){ s[t]=i+'0'; findans(s,countx,n,t+1); s[t]='X'; } } else findans(s,countx,n,t+1); } int main(int argc, char const *argv[]) { string s; cin>>s; int n; cin>>n; int countx=0; findans(s,countx,n,0); cout<<countx<<endl; return 0; } //请教各位,递归穷举为什么会超时