1. 程式人生 > >模擬(就是你想不到的做法)

模擬(就是你想不到的做法)

資料模擬題 題型總結

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 。

完美 模擬演算法。

 

 

 

 

 

 

 

 

 

 

 

4.Digital Roots

HDU - 1013

題面

通過對整數的數字求和來找到正整數的數字根。如果結果值是單個數字,則該數字是數字根。如果結果值包含兩個或更多個數字,則對這些數字求和並重復該過程。只要需要獲得一位數,這就會繼續。

例如,考慮正整數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 );
}

這也是一個小技巧吧。希望大家可以記住。