gfoj Travel Porrly

2 篇文章 0 订阅
2 篇文章 0 订阅

题目:http://www.gdfzoj.com/oj/contest/472/problems/1

给定n个数1,2,3...n,现在选出2个集合A和B,满足:
  1 A和B的交集不得为空
  2 A和B不得相互包含(A=B也属于相互包含)
  注意: 在这里我们认为: (A,B)和(B,A)是同一种方案
  求选出集合A和B的方案数
n<=1e13

 

来自xbc的方法:

看到这范围一看就是推公式(这点我也想到了。。。但不会推啊啊啊)

对于每个数有4种情况:

1.A   2.B   3.A交B  4.全集U-A并B 

题目限制条件可理解为:

1、2、3集合内不能为空

那么利用容斥原理即为:

ans=所有情况 - 至少1个集合空 + 至少2个集合空 - 3个集合全空

 

很容易推出公式:

ans=4^n - 3*3^n + 3*2^n - 1

 

n很大要用快速幂

 

对于除2详见:https://blog.csdn.net/scutbenson/article/details/83750020

 

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int value=100000007;

long long ksm(int x,long long y)
{
	long long a1;
	if (y==0)
		return 1;
	if (y==1)
		return x;
	a1=ksm(x,y/2);
	if (y%2==1)
		return (a1*a1*x)%value;
	else
		return (a1*a1)%value;
}

int main()
{
	long long a1,a2,a3,n,ans;
	
	freopen("a.txt","r",stdin);
	scanf("%lld",&n);
	
	a1=ksm(4,n);
	a2=ksm(3,n+1);
	a3=ksm(2,n);
	ans=(a1-a2+3*a3-1)%value;
	if (ans<0)
		ans+=value;
	ans*=50000004;
	printf("%lld\n",ans%value);
	
	
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值