2019 USP-ICMC K. Candies

链接

题意:

n 个数, 还有 L, R, 问有多少个本质不同的区间和在 L R 之间。

思路:

先考虑一个问题 , 长度为 n 的字符串, 求本质不同的子串有多少个。

  • n * (n + 1 ) / 2 然后在减去 height[i] , 这种是求总的, 然后减去重复的。
  • sa 代表排名为 i 的子串在的位置, 然后 height[i] 代表排名为 i 的子串和排名为 i - 1 的子串 重复的长度。
    所以排名为 i 的子串可以构成多少个以sa[i] 为开头的本质不同的子串? 那就是 n - (sa[i] - 1)- height[i], 把所有子串的结果加起来就好了。这样加起来就没有重复的了。

在回到这个题:

首先, 读入数据, 然后前缀和, 然后 把原有数据和前缀和离散化, 然后把 前缀和用主席树存起来。

然后考虑怎么把所有区间不重复的加起来。
把原始数据用后缀数组处理一下, 得到 sa, height,
对于排名为 i 的串, 起始位置为 sa[i] 和 排名 i - 1 的串重复 height 个,
在这里插入图片描述
所以问题转化成, 我以 sa[i] 为 起始点, 枚举 j, j 在 [l, r] 区间里面, 有多少 j 满足sum[j] - sum[sa[i] - 1] 在 L R 之间,
所以转化成了 有多少个 j , 满足 sum[j] 在 sum[sa[i]-1] + L, sum[sa[i] - 1] + R 之间, 用主席树查询。

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+100;
typedef long long ll;
ll b[N*2],L,R,sum[N],tim;
int n,a[N];
int rt[N],ls[N*40],rs[N*40],val[N*40],cnt;
void update(int &now, int l, int r, int k){
	++cnt; ls[cnt] = ls[now];
	rs[cnt] = rs[now];
	val[cnt] = val[now] + 1; now = cnt;
	if (l + 1 == r) return;
	int mid = (l + r) >> 1;
	if (k < mid) update(ls[now], l, mid, k);
	else update(rs[now], mid, r, k);
}

int ask(int pre, int now, int l, int r, int ll, int rr){
	if (ll <= l && rr >= r - 1){
		return val[now] - val[pre];
	}
	int mid = (l + r) >> 1;
	if (ll >= mid) return ask(rs[pre], rs[now], mid, r, ll, rr);
	else if (rr < mid) return ask(ls[pre], ls[now], l, mid, ll, rr); 
	else return ask(rs[pre], rs[now], mid, r, ll, rr) + ask(ls[pre], ls[now], l, mid, ll, rr);

}
namespace SA{
    int y[N*2], x[N*2], c[N*2], sa[N], rk[N], height[N];
    void get_SA(int *s, int m) {
        for (int i = 1; i <= n; ++i) ++c[x[i] = s[i]];
        for (int i = 2; i <= m; ++i) c[i] += c[i - 1];
        for (int i = n; i >= 1; --i) sa[c[x[i]]--] = i;
        for (int k = 1; k <= n; k <<= 1) {
            int num = 0;
            for (int i = n - k + 1; i <= n; ++i) y[++num] = i;
            for (int i = 1; i <= n; ++i) if (sa[i] > k) y[++num] = sa[i] - k;
            for (int i = 1; i <= m; ++i) c[i] = 0;
            for (int i = 1; i <= n; ++i) ++c[x[i]];
            for (int i = 2; i <= m; ++i) c[i] += c[i - 1]; 
            for (int i = n; i >= 1; --i) sa[c[x[y[i]]]--] = y[i], y[i] = 0;
            swap(x, y);
            x[sa[1]] = 1;   num = 1;
            for (int i = 2; i <= n; ++i)
                x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? num : ++num;
            if (num == n) break;
            m = num;
        }
    }
    void get_height(int *s) {
        int k = 0;
        for (int i = 1; i <= n; ++i) rk[sa[i]] = i;
        for (int i = 1; i <= n; ++i) {
            if (rk[i] == 1) continue; //第一名height为0
            if (k) --k;//h[i]>=h[i-1]+1;
            int j = sa[rk[i] - 1];
            while (j + k <= n && i + k <= n && s[i + k] == s[j + k]) ++k;
            height[rk[i]] = k; //h[i]=height[rk[i]];
        }
    }
};

int main(){
	scanf("%d%lld%lld",&n,&L,&R);
	for (int i = 1; i <= n; ++i){
		scanf("%d",&a[i]);
		sum[i] = sum[i-1] + a[i];
		b[++tim] = a[i];
		b[++tim] = sum[i];
	}
	sort(b+1,b+tim+1);
	tim = unique(b+1,b+tim+1) - b - 1;
	// for (int i = 1; i <= tim; ++i)
	// 	printf("%lld ",b[i]);
	// printf("\n");
	for (int i = 1; i <= n; ++i){
		a[i] = lower_bound(b+1,b+tim+1,a[i]) - b;
		int tmp = lower_bound(b+1,b+tim+ 1,sum[i]) - b;
		// printf("%lld %d\n",sum[i], tmp);
		rt[i] = rt[i-1];
		update(rt[i], 1, tim+1, tmp);	
	}

	SA::get_SA(a, tim+1);
	SA::get_height(a);
	int ans = 0,l,r;
	for (int i = 1; i <= n; ++i){
		l = lower_bound(b+1, b+tim+1,sum[SA::sa[i] - 1] + L) - b;
		r = upper_bound(b+1, b+tim+1,sum[SA::sa[i] - 1] + R) - b - 1;
		// printf("%d %d %d %d %d\n",i,l,r,SA::sa[i] - 1 + SA::height[i], n);
		if (l <= r)
			ans += ask(rt[SA::sa[i] - 1 + SA::height[i]], rt[n], 1, tim + 1, l, r);
	}
	printf("%d\n",ans);
	return 0;
}

基于STM32F407,使用DFS算法实现最短迷宫路径检索,分为三种模式:1.DEBUG模式,2. 训练模式,3. 主程序模式 ,DEBUG模式主要分析bug,测量必要数据,训练模式用于DFS算法训练最短路径,并将最短路径以链表形式存储Flash, 主程序模式从Flash中….zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值