Topcoder 551 DIV2
第三题 950分
题目:Problem Statement
Beaver Bindu has N cupcakes. Each cupcake has one of three possible colors. In this problem we will represent the colors by uppercase letters 'A', 'B', and 'C'. Two cupcakes of the same color are indistinguishable. You are given a string cupcakes consisting of exactly N characters. Each character in cupcakes gives the color of one of Bindu's cupcakes. Bindu has N friends, sitting around a round table. She wants to give each friend one of the cupcakes. Moreover, she does not want to give cupcakes of the same color to any pair of friends who sit next to each other. Let X be the number of ways in which she can hand out the cupcakes to her friends. As X can be very large, compute and return the value (X modulo 1,000,000,007).
ColorfulCupcakesDivTwo
Method:
countArrangements
Parameters:
string
Returns:
int
Method signature:
int countArrangements(string cupcakes)
(be sure your method is public)
"ABAB"
Returns: 2
"ABABA"
Returns: 0
"ABC"
Returns: 6
"BCBABBACBABABCCCCCAABBAACBBBBCBCAAA"
Returns: 741380640
题意:给一个只包含ABC的字符串,问你由所有这些字符任意组成的串符合条件的有多少个。
结果模上1000000007。条件就是某个串首位字符不同,任意相邻连个字符不相同。(串的长度不超过30)
分析:很显然,最后的结果和原始串中ABC的顺序无关,而和ABC每种字符的个数相关,
所以第一步要统计原始串中ABC的个数。之前比较SB的想法,设t0,t1,t2,表示三种字符的个数,
先算出所有的情况(t0+t1+t2)!/(t0! * t1! * t2!);然后减去两个字符相邻的情况,
但是,相邻的情况太多,无法计算,于是放弃这个思路。
于是乎,一个奇葩的想法油然而生,如果定义字符A表示x轴、字符B表示y轴、字符C表示z轴,
那么任意一个由ABC组成的字符串可以用一条从原点(0,0,0)出发终点是(t0,t1,t2)的路径表示。
规范的说:
DP[i][j][k][0]表示点(i,j,k)是字符A的所有情况。
DP[i][j][k][1]表示点(i,j,k)是字符B的所有情况。
DP[i][j][k][2]表示点(i,j,k)是字符C的所有情况。
DP[i][j][k][3]表示上述三者之和。
总结:坐标轴在算法竞赛中的应用非常奇葩,很多问题转化到坐标之后,就会有很好的解法!!
第三题 950分
题目:Problem Statement
Beaver Bindu has N cupcakes. Each cupcake has one of three possible colors. In this problem we will represent the colors by uppercase letters 'A', 'B', and 'C'. Two cupcakes of the same color are indistinguishable. You are given a string cupcakes consisting of exactly N characters. Each character in cupcakes gives the color of one of Bindu's cupcakes. Bindu has N friends, sitting around a round table. She wants to give each friend one of the cupcakes. Moreover, she does not want to give cupcakes of the same color to any pair of friends who sit next to each other. Let X be the number of ways in which she can hand out the cupcakes to her friends. As X can be very large, compute and return the value (X modulo 1,000,000,007).
Definition
Class:ColorfulCupcakesDivTwo
Method:
countArrangements
Parameters:
string
Returns:
int
Method signature:
int countArrangements(string cupcakes)
(be sure your method is public)
"ABAB"
Returns: 2
"ABABA"
Returns: 0
"ABC"
Returns: 6
"BCBABBACBABABCCCCCAABBAACBBBBCBCAAA"
Returns: 741380640
题意:给一个只包含ABC的字符串,问你由所有这些字符任意组成的串符合条件的有多少个。
结果模上1000000007。条件就是某个串首位字符不同,任意相邻连个字符不相同。(串的长度不超过30)
分析:很显然,最后的结果和原始串中ABC的顺序无关,而和ABC每种字符的个数相关,
所以第一步要统计原始串中ABC的个数。之前比较SB的想法,设t0,t1,t2,表示三种字符的个数,
先算出所有的情况(t0+t1+t2)!/(t0! * t1! * t2!);然后减去两个字符相邻的情况,
但是,相邻的情况太多,无法计算,于是放弃这个思路。
于是乎,一个奇葩的想法油然而生,如果定义字符A表示x轴、字符B表示y轴、字符C表示z轴,
那么任意一个由ABC组成的字符串可以用一条从原点(0,0,0)出发终点是(t0,t1,t2)的路径表示。
规范的说:
DP[i][j][k][0]表示点(i,j,k)是字符A的所有情况。
DP[i][j][k][1]表示点(i,j,k)是字符B的所有情况。
DP[i][j][k][2]表示点(i,j,k)是字符C的所有情况。
DP[i][j][k][3]表示上述三者之和。
那么递推的时候,可以从(i-1,j,k)(i,j-1,k),(i,j,k-1)三个方向推出(i,j,k)的情况。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<string>
#include<vector>
using namespace std;
typedef long long int Uint;
#define N 105
const Uint MOD=1000000007;
class ColorfulCupcakesDivTwo{
public:
Uint dp[N][N][N][4];
int countArrangements(string cupcakes){
int cnt[3];
memset(cnt,0,sizeof(cnt));
int n=cupcakes.size();
for(int i=0;i^n;i++)
cnt[cupcakes[i]-'A']++;
Uint ans=0;
for(int i=0;i<3;i++){
memset(dp,-1,sizeof(dp));
dp[0][0][0][0]=dp[0][0][0][1]=dp[0][0][0][2]=0;
dp[0][0][0][i]=dp[0][0][0][3]=1;
cnt[i]--;
ans=(ans - dfs(cnt[0],cnt[1],cnt[2],i) + dfs(cnt[0],cnt[1],cnt[2],3) +MOD)%MOD;
cnt[i]++;
}
return (int)((ans+MOD)%MOD);
}
Uint dfs(int i,int j,int k,int dir){
if(i<0 || j<0 || k<0)return 0;
if(dp[i][j][k][dir]!=-1)return dp[i][j][k][dir];
Uint tmp=0;
switch(dir){
case 0:tmp=(tmp-dfs(i-1,j,k,dir)+dfs(i-1,j,k,3)+MOD)%MOD;
break;
case 1:tmp=(tmp-dfs(i,j-1,k,dir)+dfs(i,j-1,k,3)+MOD)%MOD;
break;
case 2:tmp=(tmp-dfs(i,j,k-1,dir)+dfs(i,j,k-1,3)+MOD)%MOD;
break;
case 3:
tmp=(tmp+dfs(i,j,k,0))%MOD;
tmp=(tmp+dfs(i,j,k,1))%MOD;
tmp=(tmp+dfs(i,j,k,2))%MOD;
break;
default:break;
}
return dp[i][j][k][dir]=tmp;
}
};
ColorfulCupcakesDivTwo TEST;
int main(){
string str;
while(cin>>str){
printf("%d\n",TEST.countArrangements(str));
}
return 0;
}
总结:坐标轴在算法竞赛中的应用非常奇葩,很多问题转化到坐标之后,就会有很好的解法!!