洛谷-算法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;
}

​
相关推荐
SilentSamsara1 小时前
标准库精讲:collections/itertools/functools/pathlib 实战
开发语言·vscode·python·青少年编程·pycharm
逻辑驱动的ken1 小时前
Java高频面试考点场景题17
开发语言·jvm·面试·求职招聘·春招
charlie1145141911 小时前
通用GUI编程技术——图形渲染实战(三十九)——纹理与采样器:从WIC加载到GPU渲染
开发语言·c++·图形渲染·win32
love530love1 小时前
Python 3.12 解决 MediaPipe “no attribute ‘solutions‘” 终极方案:基于全版本硬核实测的避坑指南
开发语言·人工智能·windows·python·comfyui·mediapipe·solutions
爱码小白1 小时前
Python 类五大方法 完整版学习笔记
开发语言·python
Fuly10241 小时前
java面试知识点复习
java·开发语言·面试
北顾笙9801 小时前
day37-数据结构力扣
数据结构·算法·leetcode
啦啦啦_99991 小时前
1. 逻辑回归
算法·机器学习·逻辑回归
郭涤生1 小时前
std::condition_variable的使用及主要事项
开发语言·c++