天天看点

2015BJOI day1第三题 糖果candy

这是一道典型的看上去很吊,实际上很渣的题。

省选考试时我是彻底挂在了这一题上。考试前两个小时一直在推这道题的公式,结果完全往错误的方向去想了,白白浪费的大量的时间。考试后才发现这道题的公式竟然是如此的**,不禁感觉自己就是个大**。

题目大意:给你一个n * m的棋盘,k和p,让你用1 - k的数字去填满这个棋盘,要求同一行从左至右不递减,每一行之间至少有一列数字不一样。问你最后方案数模p为多少。交换两行算不同的方案。

对于10%的数据,1 <= n, m, k <= 3;

对于40%的数据,1 <= n, m, k <= 1000;

对于60%的数据,p = 1000000007;

对于100%的数据,1 <= n, m <= 100000, 1 <= p, k <= 2000000000

给出两组样例应该看得更明白些:

输入:1 3 3 10 输出:0 

输入:2 2 2 10 输出: 6

看到这个问题我们可以比较轻松地发现,只要计算出一行的方案数,就可以轻松求出总共的方案数。

而一行总共的方案数这个问题就是求一个序列,使得1 <= a1 <= a2 <= ······ <= am <= k,而这个问题并不好计算。我们可以把这个问题转化一下,变为:

求一个序列,使得1 < a1 + 1 < a2 + 2 < ······ < am + m < k + m + 1。而这个问题的方案数很明显是

2015BJOI day1第三题 糖果candy

这个问题如果用杨辉三角暴力求

2015BJOI day1第三题 糖果candy

能拿40分。。

而我们发现只需要求出

2015BJOI day1第三题 糖果candy

即可。用扩展欧几里得算法或者欧拉函数求出乘法逆元是能拿到p是质数的60分的。

但是因为数据太弱了。。。欧拉函数把合数当质数做能拿90分,而强行用中国剩余定理是100分。。。

这道题的正解也是简单的一塌糊涂。。。我们发现m是小于100000的整数,那么我们可以把小于m的质数全部求出来,然后暴力枚举每个质数,从分子里把对应指数的这些质数从分母里除去。然后就暴力做完了。答案也显而易见了。

我考试的时候都在干什么啊ORZ。。。。。。

放上我的渣代码,求轻喷。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

using namespace std;

const int MAXN = 101010;
const int MAXP = 10101;

int n, m, p, k, u[MAXN], d[MAXN];
int tot, prime[MAXP], whe[MAXN];

void init()
{
	scanf("%d%d%d%d", &n, &m, &k, &p);
	for(int i = 2; i <= m; i ++)
		if(!whe[i])
		{
			prime[tot ++] = i;
			for(int j = 2; i * j <= m; j ++)
				if(!whe[i * j])
					whe[i * j] = 1;
		}
}

void work()
{
	for(int i = 0; i < m; i ++)
	{
		u[i] = k + i;
		d[i] = i + 1;
	}
	for(int i = 0; i < tot; i ++)
	{
		int cnt = 0;
		for(int j = prime[i] - 1; j < m; j += prime[i])
			if(d[j] % prime[i] == 0)
				while(d[j] % prime[i] == 0)
					d[j] /= prime[i], cnt ++;
		int tak = (k - 1) % prime[i] + 1;
		for(int j = prime[i] - tak; j < m; j += prime[i])
			if(u[j] % prime[i] == 0)
			{
				while(u[j] % prime[i] == 0 && cnt)
					u[j] /= prime[i], cnt --;
				if(!cnt)
					break;
			}
	}
	long long int st = 1;
	for(int i = 0; i < m; i ++)
		(st *= u[i]) %= p;
	if(st < n)
		printf("0\n");
	else
	{
		long long int ans = 1;
		for(int i = 0; i < n; i ++)
		{
			(ans *= st) %= p;
			st --;
		}
		printf("%I64d\n", ans);
	}
}

int main()
{
	init();
	work();
	return 0;
}
           

继续阅读