2016长乐夏令营 Day10

73 篇文章 0 订阅
18 篇文章 0 订阅

T1:

f[i][j]:将每个数字转换为二进制数码后前八位为i的数中与后八位为j的数中的后八位数码opt操作后的最大值。对于每个位置pos查询与更新都是根号65536的

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<bitset>
using namespace std;

const int maxn = 1<<9;
const int maxm = 1E5 + 10;
typedef unsigned short UI;
const UI T = 8;

int n,opt,typ,f[maxn][maxn],g[maxn][maxn],ans1[maxm],ans2[maxm];
char ch[10];

int Read()
{
	int ret = 0;
	char c = getchar();
	while (c < '0' || '9' < c) c = getchar();
	while ('0' <= c && c <= '9') ret = ret*10 + c - '0',c = getchar();
	return ret;
}

int cal(int x,int y,int opt)
{
	if (opt == 1) return x & y;
	if (opt == 2) return x | y;
	return x ^ y;
}

void Work(UI A,UI B,int i)
{
	for (int j = 0; j < (1<<8); j++) {
		int now = f[j][B];
		now += (cal(j,A,opt)<<8);
		if (now > ans1[i]) ans1[i] = now,ans2[i] = g[j][B];
		else if (now == ans1[i]) ans2[i] += g[j][B];
	}
	for (int j = 0; j < (1<<8); j++) {
		int now = cal(j,B,opt);
		if (f[A][j] < now) f[A][j] = now,g[A][j] = 1;
		else if (f[A][j] == now) ++g[A][j]; 
	}
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
		freopen("TEST.txt","w",stdout);
    #else
		freopen("friend.in","r",stdin);
		freopen("friend.out","w",stdout);
	#endif
	
	n = Read();
	for (int i = 0; i < (1<<9); i++)
		for (int j = 0; j < (1<<9); j++)
			f[i][j] = -(1<<17),g[i][j] = 0; 
	scanf("%s",ch);
	if (ch[0] == 'a') opt = 1;
	else if (ch[0] == 'o') opt = 2;
	else opt = 3;
	typ = Read();
	for (int i = 1; i <= n; i++) {
		UI x = Read();
		UI A = (x>>T);//,B = ((x<<T)>>T);
		UI B = x<<T; B >>= T;
		Work(A,B,i);
	} 
	for (int i = 2; i <= n; i++) {
		if (typ) printf("%d %d\n",ans1[i],ans2[i]);
		else printf("%d\n",ans1[i]);
	}
	return 0;
}


T2:

g[i][j][k]:同种颜色的k辆车占据i行j列(每行都有车)的方案数
首先是C(i*j,k)但是这肯定有重复
用容斥原理
总数 - 至少一行没放车的方案 - 至少一列没放车的方案 + 至少一行一列没放车的方案...
g[i][j][k] = ∑∑(-1)^(p+q)*C(i,p)*C(j,q)*C((i-p)*(j-q),k)


f[i][j][k]:前k种颜色的车占据i行j列的方案数
f[i][j][k] = ∑∑C(i,p)*C(j,q)*f[p][q][k-1]*g[i-p][i-q][a[k]]


那么第二问的答案就是f[n][m][k]了

至于第一问∑∑C(n,i)*C(m,j)*f[n][m][k]

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<bitset>
using namespace std;

const int maxn = 3001*3000;
typedef long long LL;
const LL mo = 1e9 + 9;

int n,m,k,typ,Max,a[15];
LL ans = 0,f[31][31][11],g[31][31][901],fac[maxn],inv[maxn];

LL C(int n,int m)
{
	return fac[n]*inv[m]%mo*inv[n-m]%mo;
}

LL cal(int i,int j,int l)
{
	if (max(i,j) > a[l] || i*j < a[l]) return 0;
	LL ret = 0;
	for (int p = 0; p <= i; p++)
		for (int q = 0; q <= j; q++) {
			if ((i-p)*(j-q) < a[l]) continue;
			int x = ((p+q)&1)?-1:1;
			LL Add = C(i,p)*C(j,q)%mo*C((i-p)*(j-q),a[l])%mo;
			if (x == -1) ret = (ret - Add + mo)%mo;
			else ret = (ret + Add) % mo;
		}
	return ret;
}

LL ksm(LL x,LL y)
{
	LL ret = 1;
	for (; y; y >>= 1) {
		if (y&1) ret = ret*x%mo;
		x = x*x%mo; 
	}
	return ret;
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
		//freopen("test1.txt","w",stdout);
    #else
		freopen("chessboard.in","r",stdin);
		freopen("chessboard.out","w",stdout);
	#endif
	
	cin >> n >> m >> k;
	fac[0] = 1; inv[0] = 1;
	for (LL i = 1; i <= n*m; i++) fac[i] = fac[i-1]*i%mo;
	inv[n*m] = ksm(fac[n*m],mo-2);
	for (LL i = n*m; i >= 1; i--) 
		inv[i-1] = inv[i]*i%mo;
	for (int i = 1; i <= k; i++) scanf("%d",&a[i]),Max = max(Max,a[i]);
	cin >> typ; //g[0][0][0] = 
	f[0][0][0] = 1;
	//LL CA = cal(12,28,1);
	if (n > 30 || m > 30) {
		ans = cal(n,m,k);
		cout << ans;
	}
	else {
		for (int l = 1; l <= k; l++)
			for (int i = 1; i <= n; i++)
				for (int j = 1; j <= m; j++)
					g[i][j][l] = cal(i,j,l);
		for (int l = 1; l <= k; l++)
			for (int i = 1; i <= n; i++)
				for (int j = 1; j <= m; j++) 
					for (int p = 0; p <= i; p++)
						for (int q = 0; q <= j; q++)
							f[i][j][l] = (f[i][j][l] + C(i,p)*C(j,q)%mo*f[p][q][l-1]%mo*g[i-p][j-q][l]%mo)%mo;
		if (typ) cout << f[n][m][k] << endl;
		else {
			for (int i = 1; i <= n; i++)
				for (int j = 1; j <= m; j++)
					ans = (ans + f[i][j][k]*C(n,i)%mo*C(m,j)%mo)%mo;
			cout << ans << endl; 
		}
	}
	return 0;
}

为了方便算组合数,预处理阶乘和逆元

fac的逆元有快速计算方式:

inv[n-1] = inv[n]*n


T3:

提答。。万恶的提答

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值