模擬(就是你想不到的做法)
資料模擬題 題型總結
1.大數模擬 HDU 1212
題面:kd學長給你幾個數,問你這個數的階乘一共有幾位數,
INPUT
輸入由n個整陣列成。第一行包含一個整數n,他是要測試的情況數量,後面是n行,每行有一個整數 d (1 ≤ d ≤ 10 ^7)
OUTPUT
輸出包含在輸入中出現的整數的階乘的位數 。
SAMPLE INPUT
2
10
20
SAMPLE OUTPUT
7
19
進行普通 的 暴力計算 ,肯定會超時,於是超級厲害的 數學家(拉格朗日,牛頓,等等......)發明了 對數,直接 取 位數,並且 相加就是 指數 相乘,就將 乘法換成了 加法(妙,佩服的五體投地),weishu=log10(i) 是要對 位數取整(四捨五入)最後加1.
程式碼::
#include<stdio.h> #include<iostream> #include<math.h> using namespace std; typedef long long ll; int main() { int t,i; ll num; cin>>t; double weishu=0; while(t--) { weishu=0; cin>>num; for(i=1;i<=num;i++) //轉化為 數學公式 ,不用暴力計算。 weishu+=log10(i); //沒想到 這樣做 cout<<(int)weishu+1<<endl; //結果還要(四捨五入)加 1 } return 0; }
2.題目:
大數相加
Little boxes on the hillside.
Little boxes made of ticky-tacky.
Little boxes.
Little boxes.
Little boxes all the same.
There are a green boxes, and b pink boxes.
And c blue boxes and d yellow boxes.
And they are all made out of ticky-tacky.
And they all look just the same.
Input
The input has several test cases. The first line contains the integer t (1 ≤ t ≤ 10) which is the total number of test cases.
For each test case, a line contains four non-negative integers a, b, c and d where a, b, c, d ≤ 2^62, indicating the numbers of green boxes, pink boxes, blue boxes and yellow boxes.
Output
For each test case, output a line with the total number of boxes.
Sample Input
4
1 2 3 4
0 0 0 0
1 0 0 0
111 222 333 404
Sample Output
10
0
1
1070
首先這道題肯定不能用直接的a+b+c+d 來做(你可以試試),結果是WA,a,b,c,d的資料都小於2^62,這是很大的,一般的資料型別都不能夠裝下,只能來字串和陣列來模擬和的過程。為了使最後的各個位上的十進位制相加和進位容易一點,我們可以將字串上每一位a[i]-'0'轉化為10進位制數 倒序裝進 陣列中,在接下來的進位中,如果和大於9,直接a[i+1]++;就不會影響到下一位的加和。
程式碼:
下面是我的拙見,有些麻煩,大家可以減縮一下。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1000;
char s1[maxn];
char s2[maxn];
char s3[maxn];
char s4[maxn];
int s5[maxn];
int s6[maxn];
int s7[maxn];
int s8[maxn];
int main()
{
int n,len1,len2,len3,len4,i,j;
cin>>n;
while(n--)
{
memset(s1,0,sizeof(s1));
memset(s2,0,sizeof(s2));
memset(s3,0,sizeof(s3));
memset(s4,0,sizeof(s4));
memset(s5,0,sizeof(s5));
memset(s6,0,sizeof(s6));
memset(s7,0,sizeof(s7));
memset(s8,0,sizeof(s8));
scanf("%s%s%s%s",s1,s2,s3,s4);
len1=strlen(s1);
len2=strlen(s2);
len3=strlen(s3);
len4=strlen(s4);
int smax=max(max(len1,len2),max(len3,len4));
for(i=0,j=len1-1;j>=0;i++,j--)
s5[i]=s1[j]-'0';
for(i=0,j=len2-1;j>=0;i++,j--)
s6[i]=s2[j]-'0';
for(i=0,j=len3-1;j>=0;i++,j--)
s7[i]=s3[j]-'0';
for(i=0,j=len4-1;j>=0;i++,j--)
s8[i]=s4[j]-'0';
for(i=0;i<=smax;i++)
{
if(s5[i]+s6[i]+s7[i]+s8[i]>9)
{
s5[i+1]+=(s5[i]+s6[i]+s7[i]+s8[i])/10;
s5[i]=(s5[i]+s6[i]+s7[i]+s8[i])%10;
}
else
{
s5[i]=s5[i]+s6[i]+s7[i]+s8[i];
}
}
if(s5[smax]!=0)
smax++;
for(i=smax-1;i>=0;i--)
cout<<s5[i];
cout<<endl;
}
return 0;
}
在我寫程式碼的時候,在最後實行加和的時候,總找不好 倒序 輸出 加和完的陣列。因為陣列長度 分為如下情況 (陣列已經加和好了)1.前一位加和沒有進位 2.前一位的加和進位 2個情況 。 在這裡 (在陣列加和之前)我們就事先 判斷 每個陣列(資料在的陣列)長度的最大值 的 下一位 ,如果下一位 是0 的話,位數就不會加,如果下一位不是0,說明已經前一位 已經進位,這時,位數要++,最後倒序輸出。
3.題目
從我開始是模擬演算法
題面:
XYZ-26進位制數是一個每位都是大寫字母的數字。 A、B、C、…、X、Y、Z 分別依次代表一個0 ~ 25 的數字,一個 n 位的26進位制數轉化成是10進位制的規則如下
A0A1A2A3…An-1 的每一位代表的數字為a0a1a2a3…an-1 ,則該XYZ-26進位制數的10進位制值就為
m = a0 * 26^(n-1) + a1 * 26^(n-2) + … + an-3* 26^2 + an-2*26 + an-1
一天vivi忽然玩起了浪漫,要躲在學校的一個教室,讓楓冰葉子去找,當然,她也知道楓冰葉子可不是路痴,於是找到了XYZ的小蝦和水域浪子幫忙,他們會在vivi藏的教室的門口,分別寫上一個XYZ-26進位制數,分別為 a 和 b,並且在門鎖上設定了密碼。顯然,只有找到密碼才能開啟鎖,順利進入教室。這組密碼被XYZ的成員稱為lovekey。慶幸的是,楓冰葉子知道lovekey是 a的10進位制值與b的10進位制值的和的XYZ-26進位制形式。當然小蝦和水域浪子也不想難為楓冰葉子,所以a 和 b 的位數都不會超過200位。
例如第一組測試資料
a = 0 * 26^5+0* 26^4+ 0* 26^3+ 0 *26^2 + 3*26 + 7 = 85
b = 1*26^2 + 2*26 + 4 = 732
則 a + b = 817 = BFL
Input
題目有多組測試資料。
每組測試資料包含兩個值均為的XYZ-26進位制數,每個數字的每位只包含大寫字母,並且每個數字不超過200位。
Output
輸出XYZ的lovekey,每組輸出佔一行。
Sample Input
AAAADH BCE
DRW UHD
D AAAAA
Sample Output
BFL
XYZ
D
我對 字元和整形之間經過ASCLL 碼進行變換 很頭疼。接下來,我們看看解法。
很多人,包括我,也會去想用26進位制轉換為10進位制進行加法,最後再轉換回來,可行是可行,但是難操作,我們直接用26進位制的加法來寫,用整形陣列模擬一下。
程式碼:
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
char a[220], b[220];
int t1[220], t2[220];
int main()
{
while (cin >> a >> b)
{
int i, j = 0;
int a_len, b_len;
memset(t1, 0, sizeof(t1));
memset(t2, 0, sizeof(t2));
a_len = strlen(a);
b_len = strlen(b);
for (j = 0, i = a_len - 1; i >= 0; i--)
{
t1[j++] = a[i] - 'A';
}
for (j = 0, i = b_len - 1; i >= 0; i--)
{
t2[j++] = b[i] - 'A';
}
for (i = 0; i < 220; i++)
{
t1[i] = t1[i] + t2[i];
if (t1[i] >= 26)
{
t1[i] = t1[i] - 26;
t1[i + 1]++;
}
}
for (i = 220; (i >= 0) && (t1[i] == 0); i--);
if (i >= 0)
for (; i >= 0; i--)
printf("%c", t1[i] + 'A');
else
printf("A");
printf("\n");
}
return 0;
}
將字串的每位都與A距離為多少,A則是0,B是1,C是1,等等,倒序裝進 陣列中 ,再進行逐個位數的相加,如果和大於26,下一位加1。在輸出的時候 ,這裡需要一個技巧,就是 ,你不知道它從哪位開始,就有資料了。
for (i = 220; (i >= 0) && (t1[i] == 0); i--); 這個語句,就能找到那個不為0的首位數。下面 就輸出。如果全是0的話,就考慮 i這時候就是 負數,那就輸出一個 A 。
完美 模擬演算法。
題面
通過對整數的數字求和來找到正整數的數字根。如果結果值是單個數字,則該數字是數字根。如果結果值包含兩個或更多個數字,則對這些數字求和並重復該過程。只要需要獲得一位數,這就會繼續。
例如,考慮正整數24.加上2和4得到值6.由於6是單個數字,6是24的數字根。現在考慮正整數39.加上3和9的收益率12.由於12不是一個數字,因此必須重複該過程。新增1和2 yeilds 3,單個數字以及39的數字根。
Input
輸入檔案將包含一個正整數列表,每行一個。輸入的結尾將由整數值零表示。
Output
對於輸入中的每個整數,在輸出的單獨行上輸出其數字根。.
Sample Input
24
39
0
Sample Output
6
3
首先,根據題意要算資料的每個位的和,如果小於10,就輸出,如果還是大於10,就繼續加和每個位,使得,這道題沒有給你任何的資料,很有可能資料量很大,幾十位,幾百位的資料,任何一個數據型別都裝不下(會溢位),這時就應該去想用字串模擬資料,一次模擬後(int)就可以裝下了,這是就可以用遞迴,來求小於10的個位了。
也是用了模擬的思想
#include<stdio.h>
int main()
{
void fun2( int n );
char num[1000];
while( scanf("%s" ,num ) != EOF)
{
if( num[0] == '0' ) break;
int i , sum = 0;
for( i = 0 ; num[i] ; i++)
sum = sum + (num[i] - '0');
if( sum < 10 )
printf( "%d\n" , sum );
else
fun2( sum );
}
return 0;
}
void fun2( int n )
{
int b;
b = 0;
while( n )
{
b = b + n % 10;
n = n / 10;
}
if( b >= 10 ) fun2( b );
else
printf( "%d\n" , b );
}
這也是一個小技巧吧。希望大家可以記住。