洛谷-算法2-3-分治与倍增5

P6648 CCC 2019 Triangle: The Data Structure

题目背景

在 Shuchong 的平行宇宙里,计算机学中的最重要的数据结构就是三角形。

注:因为原数据包太大,故这题缩减了一些数据,具体缩减的数据点如下:

  • Subtask 1:1 ~ 10
  • Subtask 2:1 ~ 10

所以此题拥有的测试点为:

  • Subtask 1:11 ~ 26
  • Subtask 2:11 ~ 24

若想测试本题没有的测试点请到 此处 测试。

题目描述

大小为 m 的一个三角形由 m 行组成,第 i 行包含 i 个元素。

并且,这些行必须排为等边三角形的形状。

比如说,以下是一个 m=4 的三角形。

每个三角形还包含子三角形。

比如说上面这个三角形,包含:

  • 10 个大小为 1 的三角形。
  • 6 个大小为 2 的三角形。
  • 3 个大小为 3 的三角形。

注意,每个三角形都是自身的子三角形。

现在给定一个大小为 n 的三角形,求对于每个大小为 k 的子三角形,子三角形内几个数的最大值的和。

输入格式

第一行两个整数 n,k 代表三角形的大小和要求的子三角形的大小。

接下来 n 行第 i 行有 i 个整数代表这个三角形。

输出格式

一行一个整数代表对于每个大小为 k 的子三角形,子三角形内几个数的最大值的和。

输入输出样例

输入 #1复制

复制代码
4 2
3
1 2
4 2 1
6 1 4 2

输出 #1复制

复制代码
23

说明/提示

数据规模与约定
  • Subtask 1(25 pts):n≤1000。
  • Subtask 2(75 pts):无特殊限制。

对于 100% 的数据,1≤k≤n≤3000,0≤ 三角形内每个数 ≤109。

说明

翻译自 CCC 2019 Senior T5 Triangle: The Data Structure

翻译者:@一只书虫仔

实现代码:

cpp 复制代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ch() getchar()
#define pc(x) putchar(x)
template<typename T>inline void read(T&x){
	int f;char c;
	for(f=1,c=ch();c<'0'||c>'9';c=ch())if(c=='-')f=-f;
	for(x=0;c<='9'&&c>='0';c=ch())x=x*10+(c&15);x*=f;
}
template<typename T>inline void write(T x){
	static char q[64];int cnt=0;
	if(!x)pc('0');if(x<0)pc('-'),x=-x;
	while(x)q[cnt++]=x%10+'0',x/=10;
	while(cnt--)pc(q[cnt]);
}
const int maxn=3005;
int cnt,s[15],dp[2][maxn*maxn/2][2],sm[maxn];
int main(){
	int n,k;
	read(n),read(k);
	int ck=k;
	while(ck>1){
		s[cnt++]=ck;
		ck=(ck+(ck&1))>>1;
	}
	for(int i=2;i<=n;++i)sm[i]=sm[i-1]+i-1;
	for(int i=1,a;i<=n;++i)
		for(int j=1;j<=i;++j)
			read(a),dp[cnt&1][sm[i]+j][0]=dp[cnt&1][sm[i]+j][1]=a;
	for(int c=cnt-1;~c;--c){
		int o=c&1,_o=!o,sk=s[c],nt=(s[c]+(s[c]&1))>>1;
		for(int i=1;i<=n;++i){
			for(int j=1;j<=i;++j){
				for(int rv=0;rv<2;++rv){
					int re=0;
					if(!rv&&i+sk-1>n)continue;
					if(rv&&i-sk+1<1)continue;
					if(!rv){
						re=max(re,dp[_o][sm[i]+j][false]);
						re=max(re,dp[_o][sm[i+sk-nt]+j][false]);
						re=max(re,dp[_o][sm[i+sk-nt]+j+sk-nt][false]);
						re=max(re,dp[_o][sm[i+sk-1]+j+nt-1][true]);
					}
					else{
						re=max(re,dp[_o][sm[i]+j][true]);
						re=max(re,dp[_o][sm[i-sk+nt]+j][true]);
						re=max(re,dp[_o][sm[i-sk+nt]+j-sk+nt][true]);
						re=max(re,dp[_o][sm[i-sk+1]+j-nt+1][false]);
					}
					dp[o][sm[i]+j][rv]=re;
				}
			}
		}
	}
	long long ans=0;
	for(int i=1;i<=n-k+1;++i){
		for(int j=1;j<=i;++j){
			ans+=dp[0][sm[i]+j][false];
		}
	}
	write(ans),pc('\n');
	return 0;
}

P7562 JOISC 2021 イベント巡り 2 (Event Hopping 2) (Day4)

题目背景

如果无法在洛谷下载测试数据,可以 点此 下载所有数据。

题目描述

IOI Park 将有 n 场活动。

这些活动的编号从 1 到 n。 活动 i 从时间 Li​+10−1 到时间 Ri​−10−1 举行。数据保证 Li​ 和 Ri​ 是整数。

JOI 君决定参加其中的 k 个活动。但是,JOI 君不能在中间加入或离开每个活动。在两个活动场所间移动的时间忽略不计

JOI 君希望参加编号较小的活动。严格来说,JOI 君参加的 k 个活动的编号依次为 a1​,⋯,ak​,其中 1≤a1​<⋯<ak​≤n。如果序列 (a1​,⋯,ak​) 的编号小于 (b1​,⋯,bk​),当且仅当存在 j (1≤j≤k) 满足在区间 1,j−1 里的所有 l 都有 al​=bl​ 和 aj​<bj​。

给出每个活动的信息和 JOI 君参加的活动个数 k,判断 JOI 君是否可以参加 k 个活动,如果可以,输出所有的 k 个活动的编号。

输入格式

第一行,两个正整数 n,k。

第 2∼n+1 行,每行 2 个正整数,Li​,Ri​。

输出格式

如果 JOI 君可以参加 k 个活动:

  • 输出 k 行。
  • 我们设 JOI 君参与的 k 个活动的编号为 a1,a2,⋯,ak (1≤a1<⋯<ak≤n),你需要在第 j 行输出 aj (1≤j≤k)。 请注意,序列 (a1,⋯,ak) 必须是 最小字典序

如果 JOI 君无法参加 k 个活动,输出 -1。

输入输出样例

输入 #1复制

复制代码
5 4
1 3
2 5
8 9
6 8
10 15

输出 #1复制

复制代码
1
3
4
5

输入 #2复制

复制代码
4 3
1 4
3 5
4 9
7 10

输出 #2复制

复制代码
-1

输入 #3复制

复制代码
10 6
77412002 93858605
244306432 318243514
280338037 358494212
439397354 492065507
485779890 529132783
571714810 632053254
659767854 709114867
718405631 733610573
786950301 815106357
878719468 899999649

输出 #3复制

复制代码
1
2
4
6
7
8

输入 #4复制

复制代码
20 16
250732298 258217736
26470443 34965880
252620676 260043105
692063405 697656580
497457675 504191511
391372149 397942668
858168758 867389085
235756850 241022021
585764751 593366541
207824318 217052204
661682908 671226688
886273261 892279963
770109416 778960597
264372562 270395107
176883483 186662376
509929119 519063796
109491630 118520141
162731982 168101507
662727316 668317158
757072772 765493222

输出 #4复制

复制代码
1
2
4
5
6
7
8
9
10
11
12
13
14
15
16
17

说明/提示

样例 #1 解释

有 2 种方式可以参加正好 4 个活动。

  • 参加 1,3,4,5;
  • 参加 2,3,4,5。

数列 (1,3,4,5) 比数列 (2,3,4,5) 字典序小,所以输出 1,3,4,5。

样例 #2 解释

无论怎么选择都不可能正好参加 3 个活动,所以输出 −1。

样例 #3 解释

本样例满足所有 Subtask 的条件。

数据规模与约定

因洛谷限制,本题不予评测每个 Subtask 的第 1∼20 个测试点。

本题采用 Subtask 计分法。

Subtask 分值占比百分率 n Li​
1 7% / Li​≤Li+1​ (1≤i≤n−1)
2 1% ≤20 /
3 31% ≤3×103 /
4 61% / /

注:斜线表示无特殊限制。

对于 100% 的数据:

  • 1≤n≤105;
  • 1≤k≤n;
  • 1≤Li<Ri≤109(1≤i≤n)。
说明

本题译自 第20回日本情報オリンピック 2020/2021春季トレーニング合宿 - 競技 4 - T1 日文题面

实现代码:

复制代码
​
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
#define N 100005
#define pr pair<int,int>
#define mp make_pair
#define IT set< pr > :: iterator
using namespace std;
const int INF=1000000007;
int n,k,c0,cnt,ck[N << 1];
int a0,ans[N];
map< pr , int >H;
int st[N << 1][22];
void ckmax(int &x,int y)
{
    x=(x>y)?x:y;
}
struct seg
{
    int l,r;
    bool operator < (const seg &A) const
    {
        return r<A.r;
    }
}g[N],h[N];
int calc(int l,int r)
{
    if (l>r)
        return 0;
    if (H.find(mp(l,r))!=H.end())
        return H[mp(l,r)];
    int e(0),x(r);
    for (int i=20;i>=0;--i)
        if (st[x][i]>=l)
            e+=(1 << i),x=st[x][i];
    return H[mp(l,r)]=e;
}
set< pr >ps;
int main()
{
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;++i)
        scanf("%d%d",&g[i].l,&g[i].r),ck[++c0]=g[i].l,ck[++c0]=g[i].r;
    sort(ck+1,ck+c0+1);
    c0=unique(ck+1,ck+c0+1)-ck-1;
    for (int i=1;i<=n;++i)
    {
        g[i].l=lower_bound(ck+1,ck+c0+1,g[i].l)-ck;
        g[i].r=lower_bound(ck+1,ck+c0+1,g[i].r)-ck;
        h[i]=g[i];
    }
    sort(h+1,h+n+1);
    int o(1);
    for (int i=1;i<=c0;++i)
    {
        memcpy(st[i],st[i-1],sizeof(st[i-1]));
        while (o<=n && h[o].r==i)
        {
            int l(h[o].l);
            ckmax(st[i][0],l);
            ++o;
        }
        for (int j=1;st[i][j-1] && j<=20;++j)
            st[i][j]=st[st[i][j-1]][j-1];
    }
    cnt=calc(1,c0);
    if (cnt<k)
    {
        puts("-1");
        return 0;
    }
    for (int i=1;i<=n;++i)
    {
        int l(g[i].l),r(g[i].r);
        IT it=ps.upper_bound(mp(r-1,INF));
        int cl,cr;
        if (it==ps.end())
            cr=c0; else
            cr=it->first;
        if (it==ps.begin())
            cl=1; else
            --it,cl=g[it->second].r;
        if (cl>l)
            continue;
        int t0(calc(cl,cr)),t1(calc(cl,l)),t2(calc(r,cr));
        if (cnt-t0+t1+t2+1>=k)
        {
            ans[++a0]=i;
            cnt=cnt-t0+t1+t2+1;
            ps.insert(mp(l,i));
            if (a0==k)
                break;
        }
    }
    for (int i=1;i<=a0;++i)
        printf("%d\n",ans[i]);
    return 0;
}

​
相关推荐
郑州光合科技余经理11 小时前
本地生活服务系统:模块边界与结算字段怎么拆
java·开发语言·前端·后端·系统架构·uni-app·php
小灰灰搞电子11 小时前
C++ 引用折叠详解
c++
专注仿真11 小时前
Spring AI 实现智能对话系统项目指南
数据结构·spring·机器学习
来了就未晚11 小时前
Python基础 学习代码存储与命名规范
开发语言·python·学习
靠沿11 小时前
贪心算法专题(二)
算法·贪心算法
布莱克60511 小时前
数组详解:定义、作用、应用场景及与链表的区别(C/C++ 代码讲解)
c语言·开发语言·c++·数组
间歇性努力持续性发呆的野生快乐选手11 小时前
高级数据结构:树状数组
数据结构
hongmai66688812 小时前
MP2348GTL-Z:这颗24V/4A同步降压芯片,把性能和体积平衡得恰到好处
c语言·开发语言·arm开发·单片机·5g
多弗朗皮卡丘12 小时前
C语言梦开始的地方19:文件操作
c语言·开发语言
Dovis(誓平步青云)12 小时前
折叠屏悬停看视频,上半屏和下半屏应该各做什么
android·java·服务器·开发语言·安全·音视频