Codeforces Round #180 (Div. 1)(完全)

题目链接

ps:这场的题解非常nice啊,还提供了各种插图,在理解的过程中感受了出题人思维的强大啊

官方题解



非常非常非常非常非常难的比赛,反正还是由于我太弱了。。。

 A:略

B:略

C : 构造题,看到下面这张图片就懂了。。。。


深蓝色的部分是unique的,大红色的部分也是unique的,各占据了三分之二。。。。。

D:构造题

如果k=1,那么就是无脑判断了。。。。

如果k>=2,一定有解,我们就假设k=2.

如果h<w我们可以先满足每一行,放好当前行后,与上一行比较,如果非法的情况超过了一半,就将当前行的两种颜色互换(取反),这样的话当前行还是全部满足条件,与上一行之间的合法数量也>=一半,因此,这样子一行行下来的总合法量肯定超过了3/4,神构造啊,,,,,,

E: 官方题解 

计数题,突破口在于三条线的相交方式只有五种,然后我们要计算其中的两种的总数,但是由于直接算比较难,于是可以反过来求

fiveways

即求C(n,3)减去川字型,减去XD形状的,再减去H形状的,主要就是要算两个东东。

1:一条直线内有几条线段,这个可以用树状数组来求,每次遍历到一个线段的右端点就把左端点插进来(先求和再插),划一划就明白了。

2:求一条线与几条线相交,这个可以根据上面的来求,因为减去在内部的线段*2之后的点都是在这条线内的孤立的点的个数,,,自然是相交的

其他的看看代码就能想明白了。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAX_N = 222222;
int c[MAX_N];
void update(int x)
{
	for(;x<MAX_N;x+=x&-x) c[x]++;
}
int sum(int x)
{
	int ans = 0;
	for(;x;x-=x&-x) ans += c[x];
	return ans;
}
int a[MAX_N] , b[MAX_N] , p[MAX_N] , in[MAX_N] , id[MAX_N] ,inter[MAX_N];
int main()
{
	int n;
	cin >> n;
	for(int i = 1; i <= n; i++) 
	{
		cin >> a[i] >> b[i];
		if(a[i] > b[i]) swap(a[i],b[i]);
		id[a[i]] = id[b[i]] = i;
		p[a[i]] = b[i];
		p[b[i]] = a[i];
	}
	int m = 2 * n;
	for(int i = 1; i <= m; i++)
	{
		if(p[i] < i)
		{
			in[id[i]] = sum(i) - sum(p[i]-1);
			update(p[i]);
		}
	}
	for(int i = 1; i <= n; i++)
	{
		inter[i] = b[i] - a[i] - 1 - 2 * in[i];
	}
//	for(int i = 1; i <= n; i++) printf("%d ",inter[i]);
	long long ans = (long long)n*(n-1)*(n-2) / 6;
	long long chuang = 0 , cha = 0;
	for(int i = 1; i <= n; i++)
	{
		cha   += (long long)inter[i] * (n-1-inter[i]);
		chuang+= (long long)in[i] * (n-1-in[i]-inter[i]);
	}
	cout<<ans-cha/2-chuang<<endl;
	return 0;
}



summary : 好强大的一场题目啊,这种题是怎么被想出来的,我这么挫该如何拯救!!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值