暴力求解技巧(氣死你也想不到)
Ignatius and the Princess IV
來自 HDU - 1029
題面:
給你n個數字,請你找出出現至少(n+1)/2次的數字。
輸入
本題包含多組資料,請處理到EOF:
每組資料包含兩行。
第一行一個數字N(1<=N<=999999) ,保證N為奇數。
第二行為N個用空格隔開的整數。
輸出
對於每組資料,輸出一行,表示要求找到的那個數
樣例輸入
5
1 3 2 3 3
11
1 1 1 1 1 5 5 5 5 5 5
7
1 1 1 1 1 1 1
樣例輸出
3
5
1
看到這裡 ,相信大家都已經有了想法,暴力?高大上的解法?還是先PASS,有的時候(資料量不是特別大的時候),就可以先過一發暴力,如果不行,再換其他方法。我先附上暴力解法:
#include<stdio.h> #include<iostream> #include<string.h> using namespace std; int a[1000000]; int main() { int i; int n; int num; while(cin>>n) { memset(a,0,sizeof(a)); for(i=0;i<n;i++) { cin>>num; a[num]++; if(a[num]==(n+1)/2) { cout<<num<<endl; } } } return 0; }
耗時998ms 快要超時了,對於我這個新手,這個暴力用的方法也是使我大吃一驚,用陣列的下標來模擬這些數字,而陣列中的值就是這個下標出現的次數。很妙。其實還有不用暴力的解法:
#include<stdio.h> #include<algorithm> using namespace std; int a[1000000]; int main() { int i,n; while(scanf("%d",&n)!=EOF) { for(i=0;i<n;i++)scanf("%d",&a[i]); sort(a,a+n); printf("%d\n",a[(n+1)/2-1]); } return 0; }
先把陣列的資料排序,然後 直接 去找那個下標(n+1)/2 ,在陣列的位置需要 -1,就直接找出答案。
如果滿足的資料在前面,那麼(n+1)/2-1就是在滿足資料的最後的那一位。如果滿足的資料在最後的話:
滿足資料在中間的話也是滿足的:
看來是排序讓他保證了不會錯。耗時202ms ,是很好了。
2.美素數
題面:
小明對數的研究比較熱愛,一談到數,腦子裡就湧現出好多數的問題,今天,小明想考考你對素數的認識。
問題是這樣的:一個十進位制數,如果是素數,而且它的各位數字和也是素數,則稱之為“美素數”,如29,本身是素數,而且2+9 = 11也是素數,所以它是美素數。
給定一個區間,你能計算出這個區間內有多少個美素數嗎?
Input
第一行輸入一個正整數T,表示總共有T組資料(T <= 10000)。
接下來共T行,每行輸入兩個整數L,R(1<= L <= R <= 1000000),表示區間的左值和右值。
Output
對於每組資料,先輸出Case數,然後輸出區間內美素數的個數(包括端點值L,R)。
每組資料佔一行,具體輸出格式參見樣例。
Sample Input
3
1 100
2 2
3 19
Sample Output
Case #1: 14
Case #2: 1
Case #3: 4
這個題也是,起初想到了 暴力遍歷,判斷,結局不用說,肯定超時,又想到素數打表,但是很奇怪,還是超時。
const int maxn=10000000;
bool vis[maxn];
int Prime[maxn];
int cnt;
void fun()
{
cnt = 0;
memset(vis,true,sizeof(vis));
vis[0] = vis[1] = false;
vis[2] = true;
for(int i = 2 ; i<=maxn ; i++)
{
if(vis[i])
{
Prime[cnt++] = i;
for(int j = i+i ; j<=maxn; j+=i)
{
vis[j] = false;
}
}
}
}
這個題是個雙打表,解法很妙:
直接把每個數 是否是素數和 它每個位的和 是否是素數 ,全部打好表,來判斷,如果只打了是否它本身是不是素數,然後在輸入資料的時候,再現判斷它每個位是否是素數 ,就會超時,造成沒必要的麻煩。打完表後,這個ans[ ]陣列中的資料就是2到這個 下標範圍中所有既是素數,又是每位和 也是素數 的數量。在下面的輸入資料時 ,就直接 ans[右範圍]-ans[左範圍-1],這裡要減一個 1,陣列第一個資料位置為0。
#include<stdio.h>
#include<iostream>
#include<set>
#include<string.h>
using namespace std;
const int maxn=1000005;
typedef long long ll;
int ans[maxn];
bool vis[maxn];
int Prime[maxn];
int cnt;
void fun()
{
cnt = 0;
memset(vis,true,sizeof(vis));
vis[0] = vis[1] = false;
vis[2] = true;
for(int i = 2 ; i<=maxn; i++)
{
if(vis[i])
{
Prime[cnt++] = i;
for(int j = i+i ; j<=maxn; j+=i)
{
vis[j] = false;
}
}
}
}
int fun(int i)
{
int sum=0;
while(i)
{
sum=sum+i%10;
i=i/10;
}
return sum;
}
int main()
{
int sum=0;
fun();
for(int i=2;i<=maxn;i++)
{
if(vis[i]&&vis[fun(i)])
sum++;
ans[i]=sum;
}
int t;
cin>>t;
int kase=0;
while(t--)
{
int left,right;
cin>>left>>right;
int x=ans[right]-ans[left-1];
printf("Case #%d: %d\n",++kase,x);
}
return 0;
}
耗時 62 ms.完美。
3.Jamie and Alarm Snooze 來自 codeforces 916A
題面:
約翰喜歡睡覺。有一天,他必須以hh:mm起床。然而,他討厭醒來,所以他想通過在NICE時間設定鬧鐘來喚醒不那痛痛。然後他會每隔x分鐘按下貪睡按鈕,直到hh:mm到達,然後才會醒來。他想知道按下貪睡按鈕所需的最小次數是多少。
如果它包含數字'7',則被認為是NICE。例如,13:07和17:27是NICE,而00:48和21:34不是NICE。
請注意,警報和喚醒時間設定的時間不是同一天。 John可以設定一個NICE時間,這樣他就可以醒來...... hh:mm。
形式上,找到儘可能小的非負整數y,使得hh:mm之前的時間x·y分鐘的時間表示包含數字'7'。
約翰使用二十四小時制,所以在23:59到00:00之後。
輸入
每個輸入包含2行。
第一行是整數x(0 <x <61)。
下一行包含時間hh:mm,我們提供的形式是兩位整數,hh和mm,我們提供的時間是00:00到23:59;
產量
輸出他按下按鈕的最小次數。
Example
3 11 23
2
5 01 07
0
程式碼實現:
#include<stdio.h>
#include<iostream>
#include<math.h>
using namespace std;
int main(){
int x,h,m;
while(cin>>x){
int ans=0;
cin>>h>>m;
if(m%10==7||h%10==7) cout<<"0"<<endl;
else{
while(h%10!=7&&m%10!=7){
m-=x;
ans++;
if(m<0){
m+=60;
h--;
if(h<0) h+=24;
}
}
cout<<ans<<endl;
}
}
return 0;
}
這個題就是用暴力的解法,有個坑點,就是 時間 範圍 是00:00 到 23:59 如果時間減到 00:00以後 ,就會 再來一天 ,從 24:00再開始減時間,這個 需要考慮,還有 這句話:形式上,找到儘可能小的非負整數y,使得hh:mm之前的時間x·y分鐘的時間表示包含數字'7',時減過時間厚的時間點 要有數字 7,不是 在 x*y 時間 減去過程中出現 數字7.
上面程式碼 簡潔清晰,希望大家可以學學。如果 題目 是暴力求解的 話,可以把程式碼實現變得簡單點,將程式碼變得簡單清晰也是一種技巧吧,不用多餘的步驟,以免耗時超時。
看看我一開始過得程式碼:
#include<stdio.h>
#include<iostream>
using namespace std;
int main()
{
int n;
int h,m;
int h1,m1;
int k=0;
int shuju;
int flag=0,lock=0;
int xianzaishijian;
while(scanf("%d%d%d",&n,&h,&m)!=EOF)
{
flag=0,lock=0;
int zongshijian=h*60+m;
for(k=0;;k++)
{
flag=0,lock=0;
xianzaishijian=zongshijian-k*n;
if(xianzaishijian<0)
xianzaishijian+=24*60;
h1=xianzaishijian/60;
m1=xianzaishijian%60;
while(h1)
{
shuju=h1%10;
h1=h1/10;
if(shuju==7)
{
printf("%d\n",k);
flag=1;
break;
}
}
if(!flag)
{
while(m1)
{
shuju=m1%10;
m1=m1/10;
if(shuju==7)
{
printf("%d\n",k);
lock=1;
break;
}
}
}
if(flag||lock)
break;
}
}
return 0;
}
不忍直視,程式碼 又亂 又冗長,又不好理解。