D. Kousuke's Assignment

题目链接👈

题目描述🥰

题目思路😀

首先我们可以理解题目的意思,通过对样例的解析,我们可以发现题目需要求的是最多的非重叠的美丽区间的数量(题目里面的最大看错了还误导了好久🤣)

题目本质上就是求出最大的非交叉线段数量,所有线段的和都等于零。

而实际上这个问题也就是一个非常经典的动态规划问题,我们可以用dp[i]来表示前i个元素里面的最多的非重叠区间个数,同时我们可以用一个前缀数组pre[i]来计算前i个元素的总和,当pre[i]==pre[j] ( i < j )时,也就说明在第i个元素和第j个元素之间的线段的和为0,所以我们dp[j]=max(dp[i]+1,dp[j])

仅需选择离j最大的那一个i,但是为什么呢?
因为如果我们选择k<i的线段,那么我们就会错过线段[k+1,i]。由于这个遗漏,我们将无法找到dp[j]的正确答案。

AC代码🧠

// Problem: D. Kousuke's Assignment
// Contest: Codeforces - Codeforces Round 981 (Div. 3)
// URL: https://codeforces.com/contest/2033/problem/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

#define dev1(a) cout << #a << '=' << a << endl;
#define dev2(a, b) cout << #a << " = " << a << "  " << #b << " = " << b << endl;
#define dev3(a, b, c) cout << #a << " = " << a << "  " << #b << " = " << b << "  " << #c << " = " << c << endl;
#define dev4(a, b, c, d) cout << #a << " = " << a << "  " << #b << " = " << b << "  " << #c << " = " << c << "  " << #d << " = " << d << endl;
#define dev5(a, b, c, d, e) cout << #a << " = " << a << "  " << #b << " = " << b << "  " << #c << " = " << c << "  " << #d << " = " << d << "  " << #e << " = " << e << endl;
#define vec(a)                         \
    for (int i = 0; i < a.size(); i++) \
        cout << a[i] << ' ';           \
    cout << endl;
#define darr(a, _i, _n)               \
    cout << #a << ':';                \
    for (int ij = _i; ij <= _n; ij++) \
        cout << a[ij] << ' ';         \
    cout << endl;           
#define cin(a,n)           \
     for(int i=0;i<n;i++) \
      cin>>a[i];          
#define endl "\n"
#define pow pim
int pim(int a,int k)
{
    int res=1;
    if(a==0)return 0;
    while(k) 
    {
        if(k&1)res=(int)res*a;
        k>>=1;
        a=(int)a*a;
    }
    return res;
}
#define fi first
#define se second
#define caseT \
    int T;    \
    cin >> T; \
    while (T--)
#define int long long
// #define int __int128

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;

const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int MOD = 99999999;

// const int N = ;
int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}
 
int lcm(int a, int b)
{
    return a * b / gcd(a, b);
}
inline int read()
{
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
void solve()
{
	int n;
	cin>>n;
	vector<int>a(n+1);
	for(int i=1;i<=n;i++)cin>>a[i];
	map<int,int>hash;
	//记录的是当前前缀和的最近的下标
	vector<int>pre(n+1,0);
	//记录的是前缀和
	vector<int>first(n+1);
	//first[i]记录的是当前i位置相同前缀和的最近的下标
	hash[0]=0;
	for(int i=1;i<=n;i++)
	{
		pre[i]=pre[i-1]+a[i];
		//因为这里面的hash值记录的是前缀的最近的下标,所以不能用hash[pre[i]]来判断
		if(hash.find(pre[i])==hash.end())
		{
			//如果这个前缀是第一次出现的话,那么就把这个前缀位置赋值为-1
			first[i]=-1;
		}else first[i]=hash[pre[i]];
		hash[pre[i]]=i;
	}
	vector<int>dp(n+1,0);
	//dp[i]表示的是前i个元素的最大非重叠美丽区间的数量
	for(int i=1;i<=n;i++)
	{
		dp[i]=max(dp[i],dp[i-1]);
		if(first[i]!=-1)dp[i]=max(dp[i],dp[first[i]]+1);
	}
	cout<<*max_element(dp.begin()+1,dp.begin()+n+1)<<endl;
}

signed main()
{

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
	caseT
    solve();
    return 0;
}
/*

*/

 

 posted on 2025-03-06 16:16  熙玺  阅读(24)  评论(0)    收藏  举报

Shu-How Zの小窝

Loading...