标签:
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 60 Accepted Submission(s): 13
题意: 有n个机器人,共有m种颜色,分别分布在一个二维坐标平面上,每次移动可以向四联通的地方移动,多个机器人可以重合。 问所有机器人分别恰好走K步后,每种颜色的机器人聚集在一起,并且相邻两种颜色不聚集在一起的方案数。
题解: 一定不要读错题,这题只要求编号相邻的颜色的机器人不能聚集在一个点,于是难度锐减。 可以首先令坐标变化,x‘=x+y,y‘=x-y。 如此,当(x,y)向四联通方格发生变化时,及变化量为(+-1,0)(0,+-1)时,(x‘,y‘)的变化为(+-1,+-1)。 无论原坐标如何改变,新坐标的两维都会发生改变。 在考虑到每个新坐标唯一确定了原坐标,这就给我们一个很好的性质: 新坐标两维可以分开考虑x‘、y‘无论如何分开分别变化K次,我们都可以在原坐标上解释这种变化,并且移动步数也为K。 可以如此,先令Gx[i][S]为第i种颜色的机器人的X坐标聚集在S的方案数,Gy[i][S]同理。 然后在令f[i]为前i种颜色的机器人合法的聚集的方案数,那么利用容斥就可以计算这个东西。
1 const int N = 210, M = 25, K = 510, SIZE = 3010, MOD = 1e9 + 7; 2 struct Point { 3 int x, y; 4 5 inline void read() { 6 scanf("%d%d", &x, &y); 7 } 8 9 inline void fix() { 10 int tx = x, ty = y; 11 x = tx + ty, y = tx - ty; 12 } 13 14 inline int getCoor(int xy) const { 15 return xy ? y : x; 16 } 17 } arr[N]; 18 int n, m, k, f[N]; 19 int gather[2][M][SIZE]; 20 // coordinate -1500 ~ 1500 21 // real coordinate should be : i - 1501 22 // Size is SIZE 23 // 0 -> xcoordinate 1 -> y-coordinate 24 int dp[N], allAt[2][SIZE]; 25 26 inline int add(int x, int y) { 27 return (x + 0ll + MOD + 0ll + y) % MOD; 28 } 29 30 inline int mul(int x, int y) { 31 return ((x * 1ll * y) % MOD + MOD) % MOD; 32 } 33 34 int C[K][K]; 35 inline void init() { 36 for(int i = 0; i < K; ++i) C[i][0] = 1; 37 for(int i = 1; i < K; ++i) 38 for(int j = 1; j <= i; ++j) 39 C[i][j] = add(C[i - 1][j - 1], C[i - 1][j]); 40 } 41 42 inline int move(int st, int ed) { 43 int delta = abs(ed - st); 44 int freeMove = k - delta; 45 if(freeMove < 0 || (freeMove & 1)) return 0; 46 return C[k][freeMove / 2]; 47 } 48 49 inline void solve() { 50 for(int i = 1; i < m; ++i) f[i] += f[i - 1]; 51 for(int i = 0; i < n; ++i) arr[i].fix(); 52 53 for(int xy = 0; xy < 2; ++xy) 54 for(int i = 0; i < m; ++i) 55 for(int w = 0; w < SIZE; ++w) { 56 gather[xy][i][w] = 1; 57 for(int j = i ? f[i - 1] : 0; j < f[i]; ++j) 58 gather[xy][i][w] = mul(gather[xy][i][w], 59 move(w - 1501, arr[j].getCoor(xy))); 60 } 61 62 for(int i = 0; i < m; ++i) { 63 dp[i] = 0; 64 65 for(int xy = 0; xy < 2; ++xy) 66 for(int w = 0; w < SIZE; ++w) allAt[xy][w] = 1; 67 for(int j = i, coe = 1; j >= 0; --j, coe *= -1) { 68 int allGather[2] = {0, 0}; 69 for(int xy = 0; xy < 2; ++xy) 70 for(int w = 0; w < SIZE; ++w) { 71 allAt[xy][w] = mul(allAt[xy][w], gather[xy][j][w]); 72 allGather[xy] = add(allGather[xy], allAt[xy][w]); 73 } 74 75 int combine = mul(allGather[0], allGather[1]); 76 dp[i] = add(dp[i], mul(mul(coe, j ? dp[j - 1] : 1), combine)); 77 } 78 } 79 80 printf("%d\n", dp[m - 1]); 81 } 82 83 int main() { 84 freopen("f.in", "r", stdin); 85 init(); 86 int testCase; 87 scanf("%d", &testCase); 88 for(int testIndex = 1; testIndex <= testCase; ++testIndex) { 89 printf("Case #%d: ", testIndex); 90 scanf("%d%d%d", &n, &m, &k); 91 for(int i = 0; i < m; ++i) scanf("%d", &f[i]); 92 for(int i = 0; i < n; ++i) arr[i].read(); 93 solve(); 94 } 95 return 0; 96 }
标签:
原文地址:http://www.cnblogs.com/StupidBoy/p/5798139.html