1. 程式人生 > 實用技巧 >HDU100題簡要題解(2050~2059)

HDU100題簡要題解(2050~2059)

Problem Description
我們看到過很多直線分割平面的題目,今天的這個題目稍微有些變化,我們要求的是n條折線分割平面的最大數目。比如,一條折線可以將平面分成兩部分,兩條折線最多可以將平面分成7部分,具體如下所示。

Input
輸入資料的第一行是一個整數C,表示測試例項的個數,然後是C 行資料,每行包含一個整數n(0<n<=10000),表示折線的數量。
Output
對於每個測試例項,請輸出平面的最大分割數,每個例項的輸出佔一行。
Sample Input
2
1
2
Sample Output
2
7

阿巴阿巴阿巴,是數學題啊
看了大佬的題解才知道該怎麼做,接下來詳細說一下

根據直線分平面可知,由交點決定了射線和線段的條數,進而決定了新增的區域數。假設第n-1條折線把空間劃分為了f[n-1]個部分,那麼新增的折線為了使新增空間最多,需要與現有的2 * (n-1)條邊都相交。那麼新增的線段數為4 * (n-1)[圖中黃紫的線],射線數為2[圖中綠色的線。每條線段或射線(綠)產生一個新區域,但是折線的頭(黃色)的兩線段一共只能產生一個區域,所以新增區域的數量為4 * (n-1)-1+2,即 4 * (n-1)+1
故:

f(n)=f(n-1)+4(n-1)+2-1
    =f(n-1)+4(n-1)+1
    =f(n-2)+4(n-2)+4(n-1)+2
     ……
    =f(1)+4+4*2+……+4(n-1)+(n-1)   
    =2n^2-n+1

這裡附上一篇大佬總結的 各種分平面問題 ,供拓展學習使用

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;

int n, c;
long long f[10001];

int main() {
  while (scanf("%d", &c) != EOF) {
    while (c--) {
      scanf("%d", &n);
      for (int i = 1; i <= n; i++)
  	f[i] = 2 * n * n - n + 1;
      printf("%lld\n", f[n]);
    }
  }
  return 0;
}

Problem Description
Give you a number on base ten,you should output it on base two.(0 < n < 1000)
Input
For each case there is a postive number n on base ten, end of file.
Output
For each case output a number on base two.
Sample Input
1
2
3
Sample Output
1
10
11

就是輸出給定數的二進位制表示數,還沒進位制轉化那題刺激

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 1e7 + 1;
int n, a[maxn];

void work(int n) {
  int cnt = 0;
  while (n > 0) {
    a[++cnt] = n % 2;
    n /= 2;
  }
  for (int i = cnt; i >= 1; i--) 
    printf("%d", a[i]);
}

int main() {
  while (scanf("%d", &n) != EOF) {
    work(n);
    printf("\n");
  }
  return 0;
} 

Problem Description
Give you the width and height of the rectangle,darw it.
Input
Input contains a number of test cases.For each case ,there are two numbers n and m (0 < n,m < 75)indicate the width and height of the rectangle.Iuput ends of EOF.
Output
For each case,you should draw a rectangle with the width and height giving in the input.
after each case, you should a blank line.
Sample Input
3 2
Sample Output
+---+
|...|
|...|
+---+
ps:中間的空格為了排版用了.代替

一道無聊的畫圖題,直接模擬

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;

int n, m;

int main() {
  while (scanf("%d%d", &n, &m) != EOF) {
    for (int i = 1; i <= m + 2; i++) {
      for (int j = 1; j <= n + 2; j++) {
  	if ((i == 1 && j == 1) || (i == 1 && j == n + 2) || (i == m + 2 && j == 1) || (i == m + 2 && j == n + 2))
  	  printf("+");
  	else if (i == 1 || i == m + 2) printf("-");
  	else if (j == 1 || j == n + 2) printf("|");
  	else printf(" ");
      }
      printf("\n");
    }
    printf("\n");
  }
  return 0;
}

Problem Description
There are many lamps in a line. All of them are off at first. A series of operations are carried out on these lamps. On the i-th operation, the lamps whose numbers are the multiple of i change the condition ( on to off and off to on ).
Input
Each test case contains only a number n ( 0< n<= 10^5) in a line.
Output
Output the condition of the n-th lamp after infinity operations ( 0 - off, 1 - on ).
Sample Input
1
5
Sample Output
1
0
Hint:
Consider the second test case:
The initial condition : 0 0 0 0 0 …
After the first operation : 1 1 1 1 1 …
After the second operation : 1 0 1 0 1 …
After the third operation : 1 0 0 0 1 …
After the fourth operation : 1 0 0 1 1 …
After the fifth operation : 1 0 0 1 0 …
The later operations cannot change the condition of the fifth lamp any more. So the answer is 0.

首先先想到直接模擬,好耶!TLE妥妥的
之後就想,第n盞燈的開關狀態其實決定於其因數的個數,當其因數的個數為偶數時,它的狀態就是關著的;同理,個數為奇數時就是開著的狀態
得到程式碼

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;

int n;

int main() {
  while (scanf("%d", &n) != EOF) {
    int cnt = 0;
    for (int i = 1; i <= n; i++)
      if (n % i == 0) cnt++;
    if (cnt % 2 == 0) printf("0\n");
    else printf("1\n");
  }
  return 0;
}

Problem Description
Give you two numbers A and B, if A is equal to B, you should print "YES", or print "NO".
Input
each test case contains two numbers A and B.
Output
for each case, if A is equal to B, you should print "YES", or print "NO".
Sample Input
1 2
2 2
3 3
4 3
Sample Output
NO
YES
YES
NO

給的樣例也太坑了吧,拿到題心想“大水題?”,直接寫了個簡單的判斷交上去WA了,然後一臉懵逼
看了題解才知道,還有存在小數點的情況,例如1.000和1是相同的
於是就用制胡竄做吧,如果存在小數點的話先找到小數點,然後去掉後面無效的0,之後再用strcmp()函式對兩個制胡竄進行比較
講解穿插到了程式碼裡,看起來方便些,好多東西都是看著題解現學的...哎

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;

char s[100001], a[100001], b[100001];

void change(char s[100001]) {
  int len = strlen(s);
  int flag = 0, loc;
  //尋找是否存在小數點
  for (int i = 0; i < len; i++) {
    if (s[i] == '.') {
      flag = 1;
      loc = i;  //記錄小數點的下標
      break;
    }
  }
  //存在小數點 
  if (flag == 1) {
    //把小數點後面無效的零變成字串結束的標誌'\0',所以要倒著 
    for (int i = len - 1; i > loc; i--) {
      if (s[i] == '0') {
        s[i] = '\0';
  	len--;
      } else break;
    }
    //把小數點弄掉 
    if (s[len - 1] == '.') s[len - 1] = '\0';
  }
  return;
}

int main() {
  while (scanf("%s%s", a, b) != EOF) {
    change(a);
    change(b);
    int num = strcmp(a, b);
    if (num == 0) printf("YES\n");
    else printf("NO\n");
    memset(a, '\0', sizeof(a));
    memset(b, '\0', sizeof(b));
  }
  return 0;
}

Problem Description
we define f(A) = 1, f(a) = -1, f(B) = 2, f(b) = -2, ... f(Z) = 26, f(z) = -26;
Give you a letter x and a number y , you should output the result of y+f(x).
Input
On the first line, contains a number T.then T lines follow, each line is a case.each case contains a letter and a number.
Output
for each case, you should the result of y+f(x) on a line.
Sample Input
6
R 1
P 2
G 3
r 1
p 2
g 3
Sample Output
19
18
10
-17
-14
-4

需要注意的地方就只有:小寫字母是負的,大寫字母是正的
同時,注意加一個getchar()吞掉換行,一開始沒加調了好久都不對......

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;

int n;

int main() {
  while (scanf("%d", &n) != EOF) {
    getchar();
    while (n--) {
      char c;
      int y;
      scanf ("%c%d", &c, &y);
      getchar();
      if (c >= 'A' && c <= 'Z') printf("%d\n", y + c - 'A' + 1);
      else printf("%d\n", y - (c - 'a' + 1));
    }
  }
  return 0;
}

Problem Description
Given two rectangles and the coordinates of two points on the diagonals of each rectangle,you have to calculate the area of the intersected part of two rectangles. its sides are parallel to OX and OY .
Input
Input The first line of input is 8 positive numbers which indicate the coordinates of four points that must be on each diagonal.The 8 numbers are x1,y1,x2,y2,x3,y3,x4,y4.That means the two points on the first rectangle are(x1,y1),(x2,y2);the other two points on the second rectangle are (x3,y3),(x4,y4).
Output
Output For each case output the area of their intersected part in a single line.accurate up to 2 decimal places.
Sample Input
1.00 1.00 3.00 3.00 2.00 2.00 4.00 4.00
5.00 5.00 13.00 13.00 4.00 4.00 12.50 12.50
Sample Output
1.00
56.25

求兩個矩形的相交面積,我們做個圖

可以得知,相交部分即為(x2-x3)*(y2-y3),我們只需先處理一下輸入的長方形,再分別求出相交部分的左下及右上座標即可

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;

double x1, x2, x3, x4, z1, y2, y3, y4;

int main() {
  while (scanf("%lf%lf%lf%lf%lf%lf%lf%lf", &x1, &z1, &x2, &y2, &x3, &y3, &x4, &y4) != EOF) {
    if (x1 > x2) swap(x1, x2);
    if (z1 > y2) swap(z1, y2);
    if (x3 > x4) swap(x3, x4);
    if (y3 > y4) swap(y3, y4);
    x1 = max(x1, x3);
    z1 = max(z1, y3);
    x2 = min(x2, x4);
    y2 = min(y2, y4);
    if (x1 > x2 || z1 > y2) printf("0.00\n");
    else printf("%.2lf\n", (x2 - x1) * (y2 - z1));
  }
  return 0;
}

Problem Description
There must be many A + B problems in our HDOJ , now a new one is coming.
Give you two hexadecimal integers , your task is to calculate the sum of them,and print it in hexadecimal too.
Easy ? AC it !
Input
The input contains several test cases, please process to the end of the file.
Each case consists of two hexadecimal integers A and B in a line seperated by a blank.
The length of A and B is less than 15.
Output
For each test case,print the sum of A and B in hexadecimal in one line.
Sample Input
+A -A
+1A 12
1A -9
-1A -12
1A -AA
Sample Output
0
2C
11
-2C
-90

16進位制的A+B問題,使用llx輸入輸出,輸出時注意一下負號即可
這裡列舉出其他形式:
格式字元 格式字元意義
d:以十進位制形式輸出帶符號整數(正數不輸出符號)
o:以八進位制形式輸出無符號整數(不輸出字首O)
x:以十六進位制形式輸出無符號整數(不輸出字首OX)
u:以十進位制形式輸出無符號整數
f:以小數形式輸出單、雙精度實數
e:以指數形式輸出單、雙精度實數
g:以%f%e中較短的輸出寬度輸出單、雙精度實數
c:輸出單個字元
s:輸出字串

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;

long long n, m, sum;

int main() {
  while (scanf("%llx%llx", &n, &m) != EOF) {
    sum = n + m;
    if (sum < 0) {
      sum = -sum;
      printf("-%llX\n", sum);
    }
    else printf("%llX\n", sum);
  }
  return 0;
}

Problem Description
Given a sequence 1,2,3,......N, your job is to calculate all the possible sub-sequences that the sum of the sub-sequence is M.
Input
Input contains multiple test cases. each case contains two integers N, M( 1 <= N, M <= 1000000000).input ends with N = M = 0.
Output
For each test case, print all the possible sub-sequence that its sum is M.The format is show in the sample below.print a blank line after each test case.
Sample Input
20 10
50 30
0 0
Sample Output
[1,4]
[10,10]
(空行)
[4,8]
[6,9]
[9,11]
[30,30]

利用等差數列的性質,末項an=a1+(n-1) * d,n項和Sn=(a1+an) * n/2=a1 * n+n * (n-1) * d/2
在本題中,d=1,Sn=m,即有m=a1 * n+n * (n-1)/2,假設首項是1,我們代入m=a1 * n+n * (n-1)/2,則有n(n+1)=2m,所以項數最多隻有sqrt(2m)項
從大到小列舉1~sqrt(2m)的項數,算

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;

int n, m;

int main() {
  while (scanf("%d%d", &n, &m) != EOF) {
    if (n == 0 && m == 0) break;
    for (int i = sqrt(2 * m); i >= 1; i--) {
      int a = (m - ((i - 1) * i) / 2) / i;
      if (m == a * i + (i * (i - 1)) / 2)
      cout<< '[' << a << ',' << a + i - 1 << ']' <<endl;
    }
    cout << endl;
  }
  return 0;
}

Problem Description
據說在很久很久以前,可憐的兔子經歷了人生中最大的打擊——賽跑輸給烏龜後,心中鬱悶,發誓要報仇雪恨,於是躲進了杭州下沙某農業園臥薪嚐膽潛心修煉,終於練成了絕技,能夠毫不休息得以恆定的速度(VR m/s)一直跑。兔子一直想找機會好好得教訓一下烏龜,以雪前恥。
最近正值HDU舉辦50週年校慶,社會各大名流齊聚下沙,兔子也趁此機會向烏龜發起挑戰。雖然烏龜深知獲勝希望不大,不過迫於輿論壓力,只能接受挑戰。
比賽是設在一條筆直的道路上,長度為L米,規則很簡單,誰先到達終點誰就算獲勝。
無奈烏龜自從上次獲勝以後,成了名龜,被一些八卦雜誌稱為“動物界的劉翔”,廣告不斷,手頭也有了不少積蓄。為了能夠再贏兔子,烏龜不惜花下血本買了最先進的武器——“"小飛鴿"牌電動車。這輛車在有電的情況下能夠以VT1 m/s的速度“飛馳”,可惜電池容量有限,每次充滿電最多隻能行駛C米的距離,以後就只能用腳來蹬了,烏龜用腳蹬時的速度為VT2 m/s。更過分的是,烏龜竟然在跑道上修建了很多很多(N個)的供電站,供自己給電動車充電。其中,每次充電需要花費T秒鐘的時間。當然,烏龜經過一個充電站的時候可以選擇去或不去充電。
比賽馬上開始了,兔子和帶著充滿電的電動車的烏龜並列站在起跑線上。你的任務就是寫個程式,判斷烏龜用最佳的方案進軍時,能不能贏了一直以恆定速度奔跑的兔子。
Input
本題目包含多組測試,請處理到檔案結束。每個測試包括四行:
第一行是一個整數L代表跑道的總長度
第二行包含三個整數N,C,T,分別表示充電站的個數,電動車衝滿電以後能行駛的距離以及每次充電所需要的時間
第三行也是三個整數VR,VT1,VT2,分別表示兔子跑步的速度,烏龜開電動車的速度,烏龜腳蹬電動車的速度
第四行包含了N(N<=100)個整數p1,p2...pn,分別表示各個充電站離跑道起點的距離,其中0<p1<p2<...<pn<L
其中每個數都在32位整型範圍之內。
Output
當烏龜有可能贏的時候輸出一行 “What a pity rabbit!"。否則輸出一行"Good job,rabbit!";
題目資料保證不會出現烏龜和兔子同時到達的情況。
Sample Input
100
3 20 5
5 8 2
10 40 60
100
3 60 5
5 8 2
10 40 60
Sample Output
Good job,rabbit!
What a pity rabbit!

一開始用的貪心,發現不太對,這題的區域性最優解在整體上無法實現最優,才知道原來是一道動規題
把起點和終點都看作加油站,用一個dp[i]記錄到i點時所需要的最少時間,一種情況是從起點直接到這個點,另外的情況時從起點先到j(即dp[j]),再從j到i
那麼可能會有個疑問,就是如果到了j點還有餘量,再加油會不會有問題呢?其實不會,如果到j你不加油,那肯定是之前的某k點加油了,而那點dp[k]已計算過了,所以不再考慮j點不加油的情況

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;

int l, n, c, t, vr, vt1, vt2;
double minn, dp[101], time, tt, rt;
int p[101];

int main() {
  while (scanf("%d", &l) != EOF) {
    scanf("%d%d%d", &n, &c, &t);
    scanf("%d%d%d", &vr, &vt1, &vt2);
    for (int i = 1; i <= n; i++) cin >> p[i];
      p[n + 1] = l;
      dp[0] = 0;
      for (int i = 1; i <= n + 1; i++) {
        minn = 1e9 + 1;
  	for (int j = 0; j < i; j++) {
  	  int dis = p[i] - p[j];
  	  if (dis <= c) time = dis * 1.0 / vt1;
	  else time = c * 1.0 / vt1 + (dis - c) * 1.0 / vt2;
	  if (j != 0) time += t;
	  time += dp[j];
	  minn = min(time, minn); 
  	}
  	dp[i] = minn;
      }
      tt = dp[n + 1];
      rt = l * 1.0 / vr;
      if (tt > rt) printf("Good job,rabbit!\n");
      else printf("What a pity rabbit!\n");
  }
  return 0;
}