1001(HDU4632):Palindrome subsequence
這道題是找到一個字符串中不同的迴文數量,用區間DP來做,dp[i][j]表示區間[ i , j ]的迴文數量,然後遞歸。
思路:按照長度i從1—n循環遞歸求出結果:利用變量j從字符串的頭開始掃描。
如果s[ j ] != s[ j + i ],dp[ j ][ j + i ] = dp[ j + 1 ][ j + i ] + dp[ j ][ j + i - 1 ] - dp[ j + 1 ][ j + i - 1 ](減去重複的部分);
如果s[ j ] = s[ j + i ],dp[ j ][ j + i] = dp[ j + 1][ j + i ] + dp[ j ][ j + i - 1 ] + 1 (由於s[ j ……j + i - 1]有多少個迴文串,那麼s[ j + 1……s[ j + i ]就有多少個迴文串,所以不用減去中間的交叉部分)。
code:
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <iomanip>
#include <map>
#include <climits>
#include <set>
#include <vector>
#define N 10007
using namespace std;
string s ;
int dp[1111][1111] ;
int main()
{
int t , i , j ,count = 0 ;
scanf("%d" , &t) ;
while(t --)
{
memset(dp , 0 , sizeof(dp)) ;
cin >> s ;
int l = s.length() ;
for(i = 0 ; i < l ; i ++)
{
dp[i][i] = 1 ;
}
for(i = 1 ; i < l ; i++)
{
for(j = 0 ; j < l - i ; j ++)
{
if(s[j] != s[j + i])
dp[j][j + i] =(dp[j + 1][j + i] + dp[j][j + i - 1] - dp[j + 1][i + j - 1] + N) % N ;
else
dp[j][j + i] =(dp[j + 1][j + i] + dp[j][j + i - 1] + 1 + N) % N ;
}
}
printf("Case %d: %d\n" , ++ count , (dp[0][l-1] + N) % N) ;
}
return 0;
}
1002(HDU4633):Who's Aunt Zhang
這道題是組合數學的問題,用到了置換羣,還有循環節數。還有一個定理:Polya定理。
Polya定理:設G 是n個對象的一個置換羣,用m種顏色塗染這n個對象,則不同染色的方案數爲:
其中G={g(1),……,g(n)},c(g(i))是循環節數。
那麼本題是魔方置換羣,由於是一個立體圖形,那麼正方體的面9 *6 =54個、頂點8個、棱12個都是屬於不同的狀態。所以共有74種。但是魔方可以旋轉,所以分以下幾種情況:
1.不動:循環節數有74個,有1種情況;
2.旋轉90度(整體旋轉,以下都是):分前後旋轉、左右旋轉、順逆旋轉3種情況:
循環節數:旋轉的兩個側面3(循環節數)*2(情況)=6個,被旋轉的4個大面9個,頂點1(循環節數)*2=2個,棱1(循環節數)*3=3個,一共是6+9+2+3=20個;
3.旋轉180度:普通旋轉:前後、左右、順逆3種,一組對棱不動上下兩地面互換:12條棱6組,有6種,所以3+6=9種:
循環節數:旋轉的兩個側面5(循環節數)*2=10個,被旋轉的4個面是對面之間互換有9(循環節數)*2=18個。棱2(循環節數)*3=6個,頂點2(循環節數)*2=4種,一共有10+18+6+4=38種;
4.旋轉270度:與旋轉90度效果一樣,循環節數20個,情況3種;
5.旋轉120度(繞體對角線旋轉):8個頂點,4組體對角線,所以有4種情況:
面9(循環節數)*2=18種,棱(與體對角線鏈各個端點相連的3*2條棱)1(循環節數)*2=2個,剩下兩條棱2(循環節數)*1=2個,頂點(體對角線的兩個端點)2(循環節數)*1=2個,剩下的6個頂點2(循環節數)*1=2個,一共有18+2+2+2+2=26種
6.旋轉240度:與旋轉120度一樣。
綜上所述:見下表:
不動 | 旋轉90度 | 旋轉180度 | 旋轉270度 | 旋轉120度 | 旋轉240度 | |
循環節數 | 74 | 20 | 38 | 20 | 26 | 26 |
情況種數 | 1 | 3 | 9 | 3 | 4 | 4 |
所以G=1+3+9+3+4+4=24種情況。
將上述情況代入公式即得出答案。
PS:(1)求冪數的時候要用到快速冪,否則TLE;
(2)進行模運算的時候要對10007*24進行取模,否則對10007取模不一定被24整除。
code:
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <iomanip>
#include <map>
#include <climits>
#include <set>
#include <vector>
#define N (10007 * 24)//注意:不能把()丟掉
using namespace std;
long long mode(long long a , long long b)
{//快速冪求a^b
long long ans = 1 ;
long long t = a ;
while(b)
{
if(b & 1)
{
ans = ans * t % N ;
}
b >>= 1 ;
t = t * t % N ;
}
return ans ;
}
int main()
{
int t , n ;
long long count = 0 , ans ;
scanf("%d" , &t) ;
while(t --)
{
scanf("%d" , &n) ;
ans = (mode(n , 74) + mode(n , 20) * 3 * 2 + mode(n , 38) * 9 + mode(n , 26) * 4 * 2) % N ;
ans = ans / 24 ;
printf("Case %I64d: %I64d\n" ,++ count , ans) ;
}
return 0;
}
1008(HDU4639):Hehe
這道題是找規律的題,一開始我找規律找錯了,後來隊友說和斐波那契數有關,所以規律就是隻要找到”hehe“出現的次數就可以了。
code:
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <iomanip>
#include <map>
#include <climits>
#include <set>
#include <vector>
#define N 10007
using namespace std;
char a[11111] ;
int fab[5555] ;
void init()
{
int i ;
fab[1] = 1 ;
fab[2] = 2 ;
for(i = 3 ; i <= 5555 ; i ++)
{
fab[i] = (fab[i - 1] + fab[i - 2]) % N ;
}
}
int main()
{
int t , i , j , sum ;
cin >> t ;
init() ;
int k = 0 ;
while(t --)
{
sum = 1 ;
int ans = 1 ;
scanf("%s" , a) ;
int l = strlen(a) ;
for(i = 0 ; i <= l - 4 ; i ++)
{
if(a[i] == 'h' && a[i + 1] == 'e')
{
j = i + 2 ;
sum = 1 ;
while(1)
{
if(a[j] == 'h' && a[j + 1] == 'e')
{
sum ++ ;
j += 2 ;
}
else
break ;
}
if(sum >= 2)
{
ans = (fab[sum] * ans) % N ;
}
i = j - 1 ;
}
}
printf("Case %d: %d\n" , ++ k , ans) ;
}
return 0;
}
1011(HDU4642):Fliping game
這是一道很水的博弈,但是當時看到是和矩陣方格有關就覺得是和nim博弈有關,其實是想多了。
我們注意觀察:每次進行翻轉都會翻轉的硬幣就是最右下角的那枚硬幣,所以Alice最後要麼把右下角的從1翻到0,要麼就輸了。所以只要判斷右下角的那枚硬幣的朝向就可以了。是1則Alice勝,否則Bob勝。
code:
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <iomanip>
#include <map>
#include <climits>
#include <set>
#include <vector>
using namespace std;
int a[111][111] ;
int main()
{
int t , n , m ;
scanf("%d" , &t) ;//不能用cin,會超時
while(t --)
{
scanf("%d%d" , &n , &m) ;
for(int i = 0 ; i < n ; i ++)
for(int j = 0 ; j < m ; j ++)
scanf("%d" , &a[i][j]) ;
if(a[n - 1][m - 1] == 1)
printf("Alice\n") ;
else
printf("Bob\n") ;
}
return 0;
}