網易2017春招實習生編程題
說明:本文部分內容參考了網上一些大神的思路,這裏可能沒有列舉出來,實在抱歉,僅作爲學習參考。
1、雙核處理
時間限制:1秒
空間限制:32768K
一種雙核CPU的兩個核能夠同時的處理任務,現在有n個已知數據量的任務需要交給CPU處理,假設已知CPU的每個核1秒可以處理1kb,每個核同時只能處理一項任務。n個任務可以按照任意順序放入CPU進行處理,現在需要設計一個方案讓CPU處理完這批任務所需的時間最少,求這個最小的時間。
輸入描述:
輸入包括兩行:
第一行爲整數n(1 ≤ n ≤ 50)
第二行爲n個整數length[i](1024 ≤ length[i] ≤ 4194304),表示每個任務的長度爲length[i]kb,每個數均爲1024的倍數。
輸出描述:
輸出一個整數,表示最少需要處理的時間
輸入例子:
5
3072 3072 7168 3072 1024
輸出例子:
9216
解題思路:
這個問題轉化爲將數組分成兩部分使得兩部分的和的差最小,差最小就是說兩部分的和最接近,而且和所有數的和SUM的一半也是最接近的。假設用sum1表示第一部分的和,sum2表示第二部分的和,SUM表示所有數的和,那麼sum1+sum2=SUM。假設sum1 < sum2 那麼SUM/2-sum1 = sum2-SUM/2; 所以我們就有目標了,使得sum1<=SUM/2的條件下儘可能的大。也就是說從n個數中選出某些數,使得這些數的和儘可能的接近或者等於所有數的和的一半。
這其實就是揹包問題:
揹包容量是SUM/2. 每個物體的體積是數的大小,然後儘可能的裝滿揹包。
dp方程:dp[i][j] = max(dp[i-1][j-v[i]]+v[i], dp[i-1][j] )
dp[i][j]表示用前i個物體裝容量爲j的揹包能夠裝下的最大值,
dp[i-1][j-v[i]]+v[i]表示第i個物體裝進揹包的情況,
dp[i-1][j]表示第i件物品不裝進揹包的情況。
最終差值就是SUM-2*f[n-1][SUM/2];
轉回本題,則結果爲max(dp[n][sum/2],sum-dp[n][sum/2])
C++代碼實現:
#include <iostream>
using namespace std;
int main()
{
int a[50];
int n;
cin>>n;
int sum = 0;
for(int i=0; i<n; ++i)
{
cin>>a[i];
a[i] /= 1024;
sum += a[i];
}
int capacity = sum/2;
int **dp = new int*[n+1];
for(int i=0; i<=n; ++i)
dp[i] = new int[capacity+1];
for(int i=0; i<=n; ++i)
dp[i][0] = 0;
for(int i=0; i<=capacity; ++i)
dp[0][i] = 0;
for(int i=0; i<n; ++i)
{
for(int j=1; j<=capacity; ++j)
{
dp[i+1][j] = dp[i][j];
if(j>=a[i] && dp[i][j]<(dp[i][j-a[i]]+a[i]))
dp[i+1][j] = dp[i][j-a[i]]+a[i];
}
}
Int result = dp[n][capacity] > (sum-dp[n][capacity])?dp[n][capacity]:(sum-dp[n][capacity]);
cout<<result*1024;
for(int i=0; i<n; ++i)
delete dp[i];
delete dp;
return 0;
}
2、趕去公司
時間限制:1秒
空間限制:32768K
終於到週末啦!小易走在市區的街道上準備找朋友聚會,突然服務器發來警報,小易需要立即回公司修復這個緊急bug。假設市區是一個無限大的區域,每條街道假設座標是(X,Y),小易當前在(0,0)街道,辦公室在(gx,gy)街道上。小易周圍有多個出租車打車點,小易趕去辦公室有兩種選擇,一種就是走路去公司,另外一種就是走到一個出租車打車點,然後從打車點的位置坐出租車去公司。每次移動到相鄰的街道(橫向或者縱向)走路將會花費walkTime時間,打車將花費taxiTime時間。小易需要儘快趕到公司去,現在小易想知道他最快需要花費多少時間去公司。
輸入描述:
輸入數據包括五行:
第一行爲周圍出租車打車點的個數n(1 ≤ n ≤ 50)
第二行爲每個出租車打車點的橫座標tX[i] (-10000 ≤ tX[i] ≤ 10000)
第三行爲每個出租車打車點的縱座標tY[i] (-10000 ≤ tY[i] ≤ 10000)
第四行爲辦公室座標gx,gy(-10000 ≤ gx,gy ≤ 10000),以空格分隔
第五行爲走路時間walkTime(1 ≤ walkTime ≤ 1000)和taxiTime(1 ≤ taxiTime ≤ 1000),以空格分隔
輸出描述:
輸出一個整數表示,小易最快能趕到辦公室的時間
輸入例子:
2
-2 -2
0 -2
-4 -2
15 3
輸出例子:
42
解題思路:
採用走路的方式,最短需要(|x-x0|+|y-y0|)*walkTime;
採用走路+打的方式,最短需要(|xt-x|+|yt-y|)*walkTime+(|x2-xt|+|y2-yt|)*taxiTime。
C++代碼實現
#include <iostream>
#include <stdlib.h>
using namespace std;
typedef struct{
int x;
int y;
}Point;
int main()
{
Point carPoint[50];
Point office;
int n=0;
unsigned int walkTime=0,taxiTime=0;
unsigned int result=0,temp=0;
cin>>n;
for(int i=0; i<n; ++i)
cin>>carPoint[i].x;
for(int i=0; i<n; ++i)
cin>>carPoint[i].y;
cin>>office.x>>office.y;
cin>>walkTime>>taxiTime;
//走路需要的最短時間
result = (abs(office.x)+abs(office.y))*walkTime;
for(int i=0; i<n; ++i)
{
temp = (abs(carPoint[i].x)+abs(carPoint[i].y))*walkTime;
temp += (abs(office.x-carPoint[i].x)+abs(office.y-carPoint[i].y))*taxiTime;
if(temp<result)
result = temp;
}
cout<<result;
return 0;
}
3、調整隊形
時間限制:1秒
空間限制:32768K
在幼兒園有n個小朋友排列爲一個隊伍,從左到右一個挨着一個編號爲(0~n-1)。其中有一些是男生,有一些是女生,男生用’B’表示,女生用’G’表示。小朋友們都很頑皮,當一個男生挨着的是女生的時候就會發生矛盾。作爲幼兒園的老師,你需要讓男生挨着女生或者女生挨着男生的情況最少。你只能在原隊形上進行調整,每次調整隻能讓相鄰的兩個小朋友交換位置,現在需要儘快完成隊伍調整,你需要計算出最少需要調整多少次可以讓上述情況最少。例如:
GGBBG -> GGBGB -> GGGBB
這樣就使之前的兩處男女相鄰變爲一處相鄰,需要調整隊形2次
輸入描述:
輸入數據包括一個長度爲n且只包含G和B的字符串.n不超過50.
輸出描述:
輸出一個整數,表示最少需要的調整隊伍的次數
輸入例子:
GGBBG
輸出例子:
2
解題思路:
最後的狀態一定是:
BBBBBGGGGG或GGGGGBBBBB
所以我們對於串中第一個’B’,然後計算把它swap到第一個位置需要多少次,第二個’B’swap到第二個位置需要多少次…依次類推.. 。
然後對於’G’同理,最後取個較小值即爲答案。
C++代碼實現:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string x;
cin>>x;
int bcount=0,gcount=0,b=0,g=0;
for(int i=0; i<x.size(); ++i)
{
if(x[i]=='B')
{
bcount += (i-b);
b++;
}
else
{
gcount += (i-g);
g++;
}
}
b = (bcount<gcount)?bcount:gcount;
cout<<b;
return 0;
}
4、消除重複元素
時間限制:1秒
空間限制:32768K
小易有一個長度爲n序列,小易想移除掉裏面的重複元素,但是小易想是對於每種元素保留最後出現的那個。小易遇到了困難,希望你來幫助他。
輸入描述:
輸入包括兩行:
第一行爲序列長度n(1 ≤ n ≤ 50)
第二行爲n個數sequence[i](1 ≤ sequence[i] ≤ 1000),以空格分隔
輸出描述:
輸出消除重複元素之後的序列,以空格分隔,行末無空格
輸入例子:
9
100 100 100 99 99 99 100 100 100
輸出例子:
99 100
解題思路:
這題比較簡單,直接上代碼。
C++代碼實現:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool comp(int a,int b)
{
return a>b;
}
int main()
{
int n;
vector<int> a(1001,0);
int b[51] = {0};
cin>>n;
for(int i=1; i<=n; ++i)
{
cin>>b[i];
a[ b[i] ] = i; //記錄數字最後出現的索引
}
sort(a.begin(),a.end(),comp); //對索引進行從大到小排序
for(int i=50; i>=0; --i)
{
if(a[i]>=1)
{
if(i!=0)
cout<<b[a[i]]<<' ';
else
cout<<b[a[i]];
}
}
return 0;
}
5、魔力手環
時間限制:1秒
空間限制:32768K
小易擁有一個擁有魔力的手環上面有n個數字(構成一個環),當這個魔力手環每次使用魔力的時候就會發生一種奇特的變化:每個數字會變成自己跟後面一個數字的和(最後一個數字的後面一個數字是第一個),一旦某個位置的數字大於等於100就馬上對100取模(比如某個位置變爲103,就會自動變爲3).現在給出這個魔力手環的構成,請你計算出使用k次魔力之後魔力手環的狀態。
輸入描述:
輸入數據包括兩行:
第一行爲兩個整數n(2 ≤ n ≤ 50)和k(1 ≤ k ≤ 2000000000),以空格分隔
第二行爲魔力手環初始的n個數,以空格分隔。範圍都在0至99.
輸出描述:
輸出魔力手環使用k次之後的狀態,以空格分隔,行末無空格。
輸入例子:
3 2
1 2 3
輸出例子:
8 9 7
解題思路:
方法一:簡單的方法,循環對數組前後兩個數相加,即[j] = (a[j]+a[(j+1)%n])%100; a[i]=b[i];。但是當K過大時,程序容易超時。
方法二:利用矩陣的快速冪。如下圖。[1 2 3]經過兩輪之後,變成[8 9 7]
C++代碼實現:採用第二種方式
#include <iostream>
#include <vector>
using namespace std;
//矩陣相乘
vector<vector<int>> vertix_multiple(vector< vector<int> >&m,
vector< vector<int> >&n)
{
int row1 = m.size();
int col1 = m[0].size();
int col2 = n[0].size();
vector<vector<int>> result(row1,vector<int>(col2,0));
for(int i=0; i<row1; ++i)
{
for(int j=0; j<col2; ++j)
{
for(int k=0; k<col1; ++k)
result[i][j] = (result[i][j]+m[i][k]*n[k][j])%100;
}
}
return result;
}
//矩陣的冪
vector< vector<int> > vertix_pow(vector< vector<int> >m,int n)
{
int row = m.size();
vector<vector<int>> result(row,vector<int>(row,0));
//單位矩陣
for(int i=0; i<row; ++i)
result[i][i] = 1;
while(n)
{
if(n&1)
result= vertix_multiple(result,m);
n>>=1;
m = vertix_multiple(m,m);
}
return result;
}
int main()
{
int n,k;
cin>>n>>k;
int a[50]={0};
int result[50] = {0};
for(int i=0; i<n; ++i)
cin>>a[i];
vector< vector<int> >origin(n,vector<int>(n,0));
/*
構建矩陣:
1 0 1
1 1 0
0 1 1
*/
for(int i=0; i<(n-1); ++i)
origin[i][i] = origin[i+1][i] = 1;
origin[n-1][n-1] = origin[0][n-1] = 1;
//k次冪
origin = vertix_pow(origin,k);
for(int i=0; i<n; ++i)
{
for(int j=0; j<n; ++j)
{
result[i] = (result[i]+ a[j]*origin[j][i])%100;
}
}
for(int i=0; i<(n-1); ++i)
cout<<result[i]<<' ';
cout<<result[n-1];
}
6、工作安排
時間限制:1秒
空間限制:32768K
現在有n位工程師和6項工作(編號爲0至5),現在給出每個人能夠勝任的工作序號表(用一個字符串表示,比如:045,表示某位工程師能夠勝任0號,4號,5號工作)。現在需要進行工作安排,每位工程師只能被安排到自己能夠勝任的工作當中去,兩位工程師不能安排到同一項工作當中去。如果兩種工作安排中有一個人被安排在的工作序號不一樣就被視爲不同的工作安排,現在需要計算出有多少種不同工作安排計劃。
輸入描述:
輸入數據有n+1行:
第一行爲工程師人數n(1 ≤ n ≤ 6)
接下來的n行,每行一個字符串表示第i(1 ≤ i ≤ n)個人能夠勝任的工作(字符串不一定等長的)
輸出描述:
輸出一個整數,表示有多少種不同的工作安排方案
輸入例子:
6
012345
012345
012345
012345
012345
012345
輸出例子:
720
解題思路:
回溯法,遍歷空間樹,路徑數量即爲結果。
C++代碼實現:
#include <iostream>
using namespace std;
int work[6]={0,0,0,0,0,0};
int n = 0;
string str[6];
//回溯法
int backtrack(int t) //t表示第幾個工程師選擇某個工作
{
if(t>=n)
return 1;
int result = 0;
for(int i=0; i<str[t].length(); ++i)
{
if(work[str[t][i]-'0']==0) //第幾項工作是否已安排
{
work[str[t][i]-'0'] = 1;
result += backtrack(t+1);
work[str[t][i]-'0'] = 0;
}
}
return result;
}
int main()
{
cin>>n;
for(int i=0; i<n; ++i)
cin>>str[i];
cout<<backtrack(0);
return 0;
}
7、集合
時間限制:1秒
空間限制:32768K
小易最近在數學課上學習到了集合的概念,集合有三個特徵:1.確定性 2.互異性 3.無序性.
小易的老師給了小易這樣一個集合:
S = { p/q | w ≤ p ≤ x, y ≤ q ≤ z }
需要根據給定的w,x,y,z,求出集合中一共有多少個元素。小易才學習了集合還解決不了這個複雜的問題,需要你來幫助他。
輸入描述:
輸入包括一行:
一共4個整數分別是w(1 ≤ w ≤ x),x(1 ≤ x ≤ 100),y(1 ≤ y ≤ z),z(1 ≤ z ≤ 100).以空格分隔
輸出描述:
輸出集合中元素的個數
輸入例子:
1 10 1 1
輸出例子:
10
解題思路:
這題比較簡單,直接上代碼
C++代碼實現:
#include <iostream>
#include <map>
using namespace std;
int main()
{
unsigned int w,x,y,z;
cin>>w>>x>>y>>z;
map<double,int> result;
double temp = 0;
for(unsigned int i=w; i<=x; ++i)
{
temp = i*1.0;
for(unsigned int j=y; j<=z; ++j)
{
result[temp/j] = 1;
}
}
cout<<result.size();
return 0;
}
8、奇怪的表達式求值
時間限制:1秒
空間限制:32768K
常規的表達式求值,我們都會根據計算的優先級來計算。比如/的優先級就高於+-。但是小易所生活的世界的表達式規則很簡單,從左往右依次計算即可,而且小易所在的世界沒有除法,意味着表達式中沒有/,只有(+, - 和 )。現在給出一個表達式,需要你幫忙計算出小易所在的世界這個表達式的值爲多少
輸入描述:
輸入爲一行字符串,即一個表達式。其中運算符只有-,+,*。參與計算的數字只有0~9.
保證表達式都是合法的,排列規則如樣例所示。
輸出描述:
輸出一個數,即表達式的值
輸入例子:
3+5*7
輸出例子:
56
解題思路:
這題比較簡單,直接上代碼
C++代碼實現:
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
int main()
{
string str;
cin>>str;
int length = str.length();
int total = 0;
char last = 0; //運算符
char temp[10] = {0};
int templen = 0;
for(int i=0; i<length; )
{
if(str[i]=='+' || str[i]=='-' || str[i]=='*')
last = str[i++];
else
{
////讀取這個數字,不止一位
while(i<length && str[i]>='0' && str[i]<='9')
{
temp[templen++] = str[i++];
}
temp[templen] = 0;
switch(last)
{
case '-':
total -= atoi(temp); break;
case '+':
total += atoi(temp); break;
case '*':
total *= atoi(temp); break;
default:
last = 0; total = atoi(temp); break;
}
templen = 0;
}
}
cout<<total;
return 0;
}
9、塗棋盤
時間限制:1秒
空間限制:32768K
小易有一塊n*n的棋盤,棋盤的每一個格子都爲黑色或者白色,小易現在要用他喜歡的紅色去塗畫棋盤。小易會找出棋盤中某一列中擁有相同顏色的最大的區域去塗畫,幫助小易算算他會塗畫多少個棋格。
輸入描述:
輸入數據包括n+1行:
第一行爲一個整數n(1 ≤ n ≤ 50),即棋盤的大小
接下來的n行每行一個字符串表示第i行棋盤的顏色,’W’表示白色,’B’表示黑色
輸出描述:
輸出小易會塗畫的區域大小
輸入例子:
3
BWW
BBB
BWB
輸出例子:
3
解題思路:
這題比較簡單,直接上代碼
C++代碼實現:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string a[50];
unsigned int n,i,j;
cin>>n;
for(i=0; i<n; ++i)
cin>>a[i];
unsigned int count = 1;
unsigned int max = 1;
char lastColor = 0; //上一行的顏色
for(i=0; i<n; ++i)
{
count = 1;
lastColor = a[0][i];
j = 1;
while(j<n)
{
if(lastColor==a[j][i])
++count;
else
{
if(count>max)
max = count;
if(max>=n)
break; //最大區域快爲n
count = 1;
lastColor = a[j][i];
}
++j;
}
if(count>max)
max = count;
if(max>=n)
break; //最大區域快爲n
}
cout<<max;
return 0;
}
10、小易記單詞
時間限制:1秒
空間限制:32768K
小易參與了一個記單詞的小遊戲。遊戲開始系統提供了m個不同的單詞,小易記憶一段時間之後需要在紙上寫出他記住的單詞。小易一共寫出了n個他能記住的單詞,如果小易寫出的單詞是在系統提供的,將獲得這個單詞長度的平方的分數。注意小易寫出的單詞可能重複,但是對於每個正確的單詞只能計分一次。
輸入描述:
輸入數據包括三行:
第一行爲兩個整數n(1 ≤ n ≤ 50)和m(1 ≤ m ≤ 50)。以空格分隔
第二行爲n個字符串,表示小易能記住的單詞,以空格分隔,每個單詞的長度小於等於50。
第三行爲m個字符串,系統提供的單詞,以空格分隔,每個單詞的長度小於等於50。
輸出描述:
輸出一個整數表示小易能獲得的分數
輸入例子:
3 4
apple orange strawberry
strawberry orange grapefruit watermelon
輸出例子:
136
解題思路:
用Map
#include <iostream>
#include <map>
#include <string>
using namespace std;
int pow2(int a)
{
return a*a;
}
int main()
{
int n,m;
map<string,int> wordlist;
map<string,int> dict;
cin>>n>>m;
string temp;
for(int i=0; i<n; ++i)
{
cin>>temp;
wordlist[temp] = temp.length();
}
for(int i=0; i<m; ++i)
{
cin>>temp;
dict[temp] = 1;
}
map<string,int>::iterator it = wordlist.begin();
int total = 0;
while(it!=wordlist.end())
{
if((dict.find(it->first))!=dict.end())
total += pow2(it->second);
it++;
}
cout<<total;
return 0;
}
11、堆磚塊
時間限制:1秒
空間限制:32768K
小易有n塊磚塊,每一塊磚塊有一個高度。小易希望利用這些磚塊堆砌兩座相同高度的塔。爲了讓問題簡單,磚塊堆砌就是簡單的高度相加,某一塊磚只能使用在一座塔中一次。小易現在讓能夠堆砌出來的兩座塔的高度儘量高,小易能否完成呢。
輸入描述:
輸入包括兩行:
第一行爲整數n(1 ≤ n ≤ 50),即一共有n塊磚塊
第二行爲n個整數,表示每一塊磚塊的高度height[i] (1 ≤ height[i] ≤ 500000)
輸出描述:
如果小易能堆砌出兩座高度相同的塔,輸出最高能拼湊的高度,如果不能則輸出-1.
保證答案不大於500000。
輸入例子:
3
2 3 5
輸出例子:
5
解題思路:
不能按照0−1揹包問題去解,因爲不能保證堆砌的兩個塔高度相等。磚塊bk :for k=0∼n−1。定義h[i,j]爲使用前i塊磚能夠堆砌的低塔高度,j表示高塔和低塔的高度差。i=0∼n而j=0∼sum(bk)這樣定義的好處是可以計算出任意狀態下低塔和高塔各自的高度,且原問題就是h[n,0]。遞歸式爲:
當i=0時表示還沒有磚塊,高度差j一定爲0,j≠0爲不可能情況。需要比較的四種情況如下圖所示:
C++代碼實現:
#include <iostream>
using namespace std;
const int MIN_INT = 0x80000000;
void calculate(int *a,int n,int **h,int sum)
{
int b = 0;
h[0][0] = 0;
for(int j=1; j<=sum; ++j)
h[0][j] = MIN_INT;
for(int i=1; i<=n; i++)
{
b = a[i-1];
for(int j=0; j<=sum; ++j)
{
h[i][j] = h[i-1][j];
if((j+b)<=sum)
h[i][j] = std::max(h[i][j],h[i-1][j+b]+b);
if((b-j)>=0)
h[i][j] = std::max(h[i][j],h[i-1][b-j]+b-j);
else
h[i][j] = std::max(h[i][j],h[i-1][j-b]);
}
}
}
int main()
{
int a[50]={0};
int n;
cin>>n;
int sum = 0;
for(int i=0; i<n; ++i)
{
cin>>a[i];
sum += a[i];
}
int **h=new int*[n+1];
for(int i=0; i<=n; ++i)
h[i] = new int[sum+1];
calculate(a,n,h,sum);
if(h[n][0]>0)
cout<<h[n][0];
else
cout<<-1;
for(int i=0; i<=n; ++i)
delete h[i];
delete h;
return 0;
}
12、分餅乾
時間限制:1秒
空間限制:32768K
易老師購買了一盒餅乾,盒子中一共有k塊餅乾,但是數字k有些數位變得模糊了,看不清楚數字具體是多少了。易老師需要你幫忙把這k塊餅乾平分給n個小朋友,易老師保證這盒餅乾能平分給n個小朋友。現在你需要計算出k有多少種可能的數值
輸入描述:
輸入包括兩行:
第一行爲盒子上的數值k,模糊的數位用X表示,長度小於18(可能有多個模糊的數位)
第二行爲小朋友的人數n
輸出描述:
輸出k可能的數值種數,保證至少爲1
輸入例子:
9999999999999X
3
輸出例子:
4
解題思路:
動態規劃算法。dp[i][j]表示長度爲i的數 除以小朋友的人數之後得到的餘數爲j的個數。結果就是dp[str.length][0]
那麼狀態轉移方程該怎麼寫呢,舉個例子,對於確定的數值K=1244,小朋友個數n=3來說,如果當前的i爲走到了3,也就是我們只看124這三位,那麼算出餘數j爲1,也就是說對於這個特殊的例子dp[3][1]=1;那麼當i=4的時候,我們現在要看1244了,那我們怎麼更新呢,來看1244除以3的過程,其實前面完全就是124除以3,只不過得到過程中的餘數1之後,要和最後的4拼接構成14,再和3除,得到最後的餘數2,那這時候其實,新的餘數是j=2,也就是dp[4][2]+=dp[3][1].
上述情況如果理解了,現在就把最後那個4 換成X,那麼這時候,由於X可以從0到9,所以我們得到的新餘數應該是newJ=(1*10+X)%3,這樣由於X不定,我們可以更新很多值,但是這更新的新餘數,都來自這個舊餘數,或者依賴於他。
如果str[i]=’X’,則X可替換爲0-9
newJ = (j*10+k)%n; dp[i][newJ] += dp[i-1][j]
如果str[i]=0-9,則:
newJ = (j*10+str[i]-‘0’)%n; dp[i][newJ] += dp[i-1][j]
C++代碼實現:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str;
int n;
cin>>str;
cin>>n;
if(n<=0)
return 0;
long long **dp = new long long*[str.length()+1];
for(int i=0; i<=str.length(); ++i)
dp[i] = new long long[n];
for(int i=0; i<=str.length(); ++i)
for(int j=0; j<n; ++j)
dp[i][j] = 0;
dp[0][0] = 1;
int newJ = 0;
for(int i=1; i<=str.length(); ++i)
{
for(int j=0; j<n; ++j)
{
if(str[i-1]=='X')
{
for(int k=0; k<=9; ++k)
{
newJ = (j*10+k)%n;
dp[i][newJ] += dp[i-1][j];
}
}
else
{
newJ = (j*10+str[i-1]-'0')%n;
dp[i][newJ] += dp[i-1][j];
}
}
}
cout<<dp[str.length()][0];
for(int i=0; i<=str.length(); ++i)
delete dp[i];
delete dp;
return 0;
}