洛谷P3948 数据结构 前缀和+差分


洛谷P3948 数据结构


标签

  • 前缀和
  • 差分

简明题意

  • 需要你支持两种操作
    1. 将区间[L,R]每个数都加上x
    2. 询问[L,R]内的a[i],满足min <= a[i] * i % mod <= max,其中min,max,mod都是题目给定的

思路

  • 首先这题不是数据结构题…这题我们考虑一步步优化
    1. 写一个纯暴力,可以拿70分。
    2. 考虑到最后有很多查询,但是没有修改,我们前缀和出pre[i],表示到i为止满足 m i n &lt; = a [ i ] ∗ i min &lt;= a[i] * i % mod &lt;= max min<=a[i]i的个数,然后这里的O(n)查询就变成了O(1)…然后,我们惊奇的发现,AC了…
  • 但是我们不能就这样满足了,因为上面的操作1和操作2仍然是O(n)的。我们去考虑优化上面的操作
  • 我们可以在修改时用差分O(1)修改,然后在查询时通过差分还原出原数组,然后暴力O(n)…
  • 这样优化后大概是5000ms,不进行这一步优化,大概是8000ms
  • 结束…

注意事项

  • 用了差分再用前缀和,记得要还原两次

总结

  • 多考虑差分,前缀和,这样能将两个O(n)的操作中的其中一个降低到O(1)
  • 涉及到区间加和可以差分,统计数目可以前缀和

AC代码

#include<cstdio>

const int maxn = 8e4 + 10;

int n, m, mod, min, max;
long long a[maxn];

void solve()
{
   long long cf[maxn] = { 0 };

   scanf("%d%d%d%d%d", &n, &m, &mod, &min, &max);
   while (m--)
   {
   	char opt[10];
   	scanf("%s", opt);

   	if (opt[0] == 'A')
   	{
   		int l, r, x;
   		scanf("%d%d%d", &l, &r, &x);

   		cf[l] += x, cf[r + 1] -= x;
   	}
   	else if (opt[0] == 'Q')
   	{
   		int l, r;
   		scanf("%d%d", &l, &r);

   		long long cnt = 0, las = 0;
   		for (int i = 1; i <= n; i++)
   		{
   			long long x = las + cf[i];
   			las = x;
   			if (i >= l && i <= r && x * i % mod <= max && x * i % mod >= min)
   				cnt++;
   		}
   				
   		printf("%lld\n", cnt);
   	}
   }

   for (int i = 1; i <= n; i++)
   	a[i] = a[i - 1] + cf[i];

   int pre[maxn] = { 0 };
   for (int i = 1; i <= n; i++)
   	pre[i] = pre[i - 1] + (i * a[i] % mod >= min && i * a[i] % mod <= max);

   scanf("%d", &m);
   while (m--)
   {
   	int l, r;
   	scanf("%d%d", &l, &r);

   	printf("%d\n", pre[r] - pre[l - 1]);
   }
}

int main()
{
   freopen("Testin.txt", "r", stdin);
   solve();
   return 0;
}

双倍经验

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值