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;
}