srm500

level 3 div1

要求会:exgcd 和组合重复计数 和一些trick

其实这题只有一个小小的trick,

考虑这样一个问题如果给你2个1和1个21个4求他们能组合成的所有数的和

 共有12个数12=4!/(2!*1!*1!)  这个公式《组合数学》第3版上的重复计数上有

 
 
1124 1142 1214 1241 1412 1421 2114 2141 2411 4112 4121 4211
你会发现每列1出现了6次,2是3次,4是3次有了这个规律就好做了,仔细分析一下,任何情况都会有相似的规律
6:3:3=2:1:1 即2个1 1个2 1个4 6+3+3=12=4!/(2!*1!*1!) 
我们只需要枚举1 2 3 4 5 6 7 8 9 各出现多少次,然后o(1)就出解了。
详细题解:https://apps.topcoder.com/wiki/display/tc/SRM+500(需要挂一个vpn)推荐——穹顶穿越。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;
long long mod = 500500573;
void exgcd(long long x, long long y, long long &rev, long long &temp)
{
	if (y == 0)temp = 0, rev = 1;
	else
	{
		exgcd(y, x%y, temp, rev);
		temp -= (x / y)*rev;
		temp = temp%mod;
	}
}
long long J[3000], revJ[3000], m[3000];
void init()
{
	J[0] = 1; long long temp = 0; m[0] = 1; revJ[0] = 1;
	for (int i = 1; i <= 2500; i++)
	{
		J[i] = i*J[i - 1] % mod; exgcd(J[i], mod, revJ[i], temp); revJ[i] = (revJ[i] + mod) % mod;
		m[i] = ((10 * m[i - 1])+1) % mod;
	}
}
class ProductAndSum
{
public:
	int getSum(int p2, int p3, int p5, int p7, int s)
	{
		long long temp; long long allans = 0;
		int d[11];
		d[5] = p5; d[7] = p7;
		init();
		for (d[6] = 0; d[6] <= min(p2, p3); d[6]++)
		{
			for (d[8] = 0; d[8] <= (p2 - d[6]) / 3 + 1; d[8]++)
			{
				for (d[4] = 0; d[4] <= (p2 - 3 * d[8] - d[6]) / 2 + 1; d[4]++)
				{
					for (d[9] = 0; d[9] <= (p3 - d[6]) / 2; d[9]++)
					{
						d[2] = p2 - 2 * d[4] - d[6] - 3 * d[8]; d[3] = p3 - d[6] - 2 * d[9];
						d[1] = s - 2 * d[2] - 3 * d[3] - 4 * d[4] - 5 * d[5] - 6 * d[6] - 7 * d[7] - 8 * d[8] - 9 * d[9];
						if (d[1] < 0 || d[2] < 0 || d[3] < 0)continue;
						long long lenth = 0; long long revlenth;
						for (int i = 1; i <= 9; i++)lenth += d[i];
						exgcd(lenth, mod, revlenth, temp);
						revlenth = (revlenth + mod) % mod;
						long long k = J[lenth];
						for (int i = 1; i <= 9; i++)k = (k*revJ[d[i]]) % mod;
						lenth--; long long ans = 0;
						for (int i = 1; i <= 9; i++)
							ans += d[i] * i;
						ans = (((((ans*k) % mod)*revlenth) % mod)*m[lenth]) % mod;
						allans += ans;
					}
				}
			}
		}
		allans = allans%mod;
		return (int)allans;
	}
};
//一下代码仅用于测试:
int main()
{
	//long long q, p,mm;
	//mm = 11;
	//exgcd(3, mm, q, p);
	//cout << (q+mm)%mm << endl;
	ProductAndSum a;
	int p2, p3, p5, p7, s;
	scanf("%d%d%d%d%d", &p2, &p3, &p5, &p7, &s);
	int qq = a.getSum(p2, p3, p5, p7, s);
	cout << qq << endl;
}

250:看代码秒懂然而题意很难懂。。。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
#include<functional>
using namespace std;
typedef pair<int, int>p;
int vote[600];
class MafiaGame
{
public:
	priority_queue<p, vector<p>, greater<p>>que;
	double probabilityToLose(int N, vector<int> decisions)
	{
		double sum = 0;
		for (int i = 0; i < decisions.size(); i++)
		{
			vote[decisions[i]]++;
		}
		for (int i = 0; i < N; i++)
			que.push(p(vote[i], i));
		for (int i = 1; i <= N- decisions.size(); i++)
		{
			p temp = que.top();
			que.pop();
			vote[temp.second]++;
			que.push(p(vote[temp.second], temp.second));
		}
		int maxx = -1;
		for (int i = 0; i < N; i++)
			maxx = max(vote[i], maxx);
		for (int i = 0; i < N; i++)
			if (vote[i] == maxx)sum++;
	     double temp = sum;
		if (sum == 1)return 1;
		else
		{
			while (1)
			{
				if (sum == 0)return 0;
				if (sum == 1)return 1 / temp;
				sum = N%(int)sum;
			}
		}
	}
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值