Codeforces Round #813 (Div. 2)

D Empty Graph

感觉是被题目绕晕了,再回顾下题目
a l a_l al a r a_r ar 之间的距离为 m i n ( a i ) min(a_i) min(ai) ( i ∈ [ l , r ] ) (i∈[l,r]) (i[l,r])
a l a_l al a r a_r ar 之间的最短距离为图的一条路径
而图的直径为所有路径中最长的
我们要使图的直径最长
贪心没想好,我们选择二分答案
那么问题转换成如何 c h e c k check check 答案
我们选择的 l l l r r r 距离越远 m i n ( a i ) min(a_i) min(ai) 越小
所以我们可以直接考虑相邻点的最短距离
而最短距离为 m i n ( m a x ( a l , a r ) , m i n ( a i ) ∗ 2 ) min(max(a_l,a_r),min(a_i)*2) min(max(al,ar),min(ai)2)
我们直接枚举 1 1 1 n n n 使每个不满足 a i ∗ 2 < m i d a_i*2<mid ai2<mid a i a_i ai 设为 1 e 9 1e9 1e9
同时如果 m a x ( a l , a r ) < m i d max(a_l,a_r)<mid max(al,ar)<mid 那么我们进行分类讨论
如果在此之前我们已经修改了一个值,那么直接在该值旁白再修改一个 1 e 9 1e9 1e9 即可
否则如果此时的最大值满足 m a x ( a i ) ≥ m i d max(a_i)≥mid max(ai)mid,同理也只需修改一个值即可
否则就需要修改两个值
最后判断 s u m < = k sum<=k sum<=k 即可 s u m sum sum 为累积的修改次数

ps:

弄清题意永远比急着写题重要,已经吃了无数次亏了
在真正明白题意后,然后在写之前滤清思路能大幅增加写代码的效率,并且减少 b u g bug bug的产生,多耗费一点时间是完全值得的

int n, m, k, ma;
int a[N], b[N];

bool check(ll da)
{
	rep(i, 1, n) b[i] = a[i];
	int cnt = 0;
	rep(i, 1, n) if (b[i] * 2 < da) b[i] = 1e9, cnt++;
	bool ok = false;
	rep(i, 2, n) if (min(b[i], b[i - 1]) >= da) { ok = true; break; }
	if (!ok)
	{
		if (cnt) cnt++;
		else if (ma >= da) cnt++;
		else cnt += 2;
	}
	return cnt <= k;
}

void solve()
{
	cin >> n >> k;
	ma = 0;
	rep(i, 1, n) cin >> a[i], ma = max(ma, a[i]);
	ll l = 0, r = 1e9, mid;
	while (l < r)
	{
		mid = (l + r + 1) >> 1;
		if (check(mid)) l = mid;
		else r = mid - 1;
	}
	cout << l << endl;
}

E2 LCM Sum

显然该题要离线做
首先 l c m ( i , j , k ) ≥ 3 k lcm(i,j,k)≥3k lcm(i,j,k)3k是肯定可以的
那我们只需要考虑 l c m ( i , j , k ) = 2 k lcm(i,j,k)=2k lcm(i,j,k)=2k l c m ( i , j , k ) = k lcm(i,j,k)=k lcm(i,j,k)=k
1. l c m ( i , j , k ) = 2 k 1.lcm(i,j,k) = 2k 1.lcm(i,j,k)=2k
我们列几个例子发现只有 ( 3 , 4 , 6 ) (3,4,6) (3,4,6) ( 6 , 10 , 15 ) (6,10,15) (6,10,15) 及其倍数不符合条件
(其实这能证明的,但是我懒)
2. l c m ( i , j , k ) = k 2.lcm(i,j,k)=k 2.lcm(i,j,k)=k
k k k p p p 个因数,那么就有 C p 2 C_p^2 Cp2 个组合不符合条件
我们先存储所有的询问,并对每个区间左端点排序
我们先预处理所有 i i i 的倍数 x x x 存在 v e c t o r < i n t > p [ x ] vector<int>p[x] vector<int>p[x] 中,复杂度 O ( n l o g l o g n ) O(nloglogn) O(nloglogn)
然后从 1 1 1 200000 200000 200000 扫描,统计每个 i i i 对其倍数 x x x 的贡献
将其累加到树状数组 T . s [ x ] T.s[x] T.s[x] 中,并且对超出范围的 i i i 减去它的贡献
然后对 1 1 1 q [ i ] . r q[i].r q[i].r 树状数组求和即可

vc<int> p[N];
void get_prime()
{
	rep(i, 1, 200000)
		for (int j = i * 2; j <= 200000; j += i)
			p[i].pb(j);
}

void init()
{
	// cin >> T_T;
	get_prime();
}

int n;
ll ans[N];
struct P
{
	int l, r, id;
	bool operator<(const P &a)
	{
		return l < a.l;
	}
}q[N];

struct FW_Tree
{
	int n = 200000;ll s[N]={0};
	void init(){rep(i,1,n)s[i]=0;}
	void build(ll a[],int len)
	{n=len;rep(i,1,n){s[i]+=a[i];if(i+lowbit(i)<=n)s[i+lowbit(i)]+=s[i];}}
	void add(int i,ll x){for(;i<=n;i+=lowbit(i))s[i]+=x;}
	void add(int l,int r,ll k){add(l,k),add(r+1,-k);}
	ll ask(int i){ll ret=0;for(;i;i-=lowbit(i))ret+=s[i];return ret;}
	ll ask(int l,int r){return ask(r)-ask(l-1);}
}T;

int f[N];

void solve()
{
	cin >> n;
	rep(i, 1, n) cin >> q[i].l >> q[i].r, q[i].id = i;
	rep(i, 1, n)
	{
		ll len = q[i].r - q[i].l + 1;
		ans[i] = len * (len - 1) / 2 * (len - 2) / 3;
		ans[i] -= max(0, q[i].r / 6 - (q[i].l - 1) / 3);
		ans[i] -= max(0, q[i].r / 15 - (q[i].l - 1) / 6);
	}
	sort(q + 1, q + n + 1);
	int l = q[1].l, r = q[1].l - 1;
	rep(i, 1, n)
	{
		while (r < q[i].r)
		{
			r++;
			for (auto x : p[r]) T.add(x, f[x]++);
		}
		while (l < q[i].l)
		{
			for (auto x : p[l]) T.add(x, -(--f[x]));
			l++;
		}
		ans[q[i].id] -= T.ask(q[i].r);
	}
	rep(i, 1, n) cout << ans[i] << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值