bzoj 4597: [Shoi2016]随机序列

说实话,大大的良心题2333,我这个蒟蒻都会做2333(这是今天做出来第一个pj+难度的题2333)(太弱了)

(3^(n-1)暴力肯定是不对的2333)

现在可以发现一个奇妙的性质,就是对于一个位置,前面的全是乘号的话,那么这个位置填加和减号,那么后面产生的贡献就正好正负抵消了。而这个位置填加减号的贡献就是3^m*2*pre_sum (pre_sum指这个位置之前的数的积,m指后面还有m个位置)

如果这个位置填乘号的话,只对后面填的情况有贡献。

这样的话,对于每个位置,都有一个值(注意最后还要加上一个所有数的乘积)

这样修改的话,就是对x位置及以后的把原数除掉,乘上新数就好了。直接上弱智版的线段树就行。

 1 #include <bits/stdc++.h>
 2 #define LL long long
 3 #define inf 1e60
 4 using namespace std;
 5 inline int ra()
 6 {
 7     int x=0,f=1; char ch=getchar();
 8     while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
 9     while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
10     return x*f;
11 }
12 
13 const int maxn=100005;
14 const int mod=1e9+7;
15 
16 int ksm(int x, int p)
17 {
18     int sum=1;
19     for (;p;p>>=1,x=(LL)x*x%mod)
20         if (p&1) sum=(LL)sum*x%mod;
21     return sum;
22 }
23 
24 int inv[maxn],orz[maxn];
25 int n,T,a[maxn];
26 void pre()
27 {
28     inv[1]=1;
29     for (int i=1; i<=n; i++) orz[i]=1;
30     for (int i=2; i<=10000; i++) inv[i]=(LL)(mod-mod/i)*inv[mod%i]%mod;
31 }
32 
33 struct seg{
34     int l,r,mul,sum;
35 }t[maxn<<4];
36 void update(int k) {t[k].sum=(t[k<<1].sum+t[k<<1|1].sum)%mod;}
37 void build(int k, int l, int r)
38 {
39     t[k].l=l; t[k].r=r; t[k].mul=1; 
40     if (l==r)
41     {
42         t[k].sum=orz[l]; return;
43     }
44     int mid=l+r>>1;
45     build(k<<1,l,mid); build(k<<1|1,mid+1,r);
46     update(k);
47 }
48 void pushdown(int k)
49 {
50     int tmp=t[k].mul; t[k].mul=1;
51     t[k<<1].mul=(LL)t[k<<1].mul*tmp%mod;
52     t[k<<1].sum=(LL)t[k<<1].sum*tmp%mod;
53     t[k<<1|1].mul=(LL)t[k<<1|1].mul*tmp%mod;
54     t[k<<1|1].sum=(LL)t[k<<1|1].sum*tmp%mod;
55 }
56 void change(int k, int x, int y, int val)
57 {
58     int l=t[k].l,r=t[k].r;
59     if (l==x && y==r)
60     {
61         t[k].sum=(LL)t[k].sum*val%mod;
62         t[k].mul=(LL)t[k].mul*val%mod;
63         return;
64     }
65     int mid=l+r>>1;
66     if (t[k].mul!=1) pushdown(k);
67     if (y<=mid) change(k<<1,x,y,val);
68     else if (x>mid) change(k<<1|1,x,y,val);
69     else change(k<<1,x,mid,val),change(k<<1|1,mid+1,y,val);
70     update(k);
71 }
72 
73 int main()
74 {
75     n=ra(); T=ra(); pre();
76     for (int i=1; i<=n; i++) a[i]=ra(),orz[n]=(LL)orz[n]*a[i]%mod;
77     orz[1]=(LL)a[1]*ksm(3,n-2)*2%mod;
78     for (int i=2; i<n; i++) orz[i]=(LL)orz[i-1]*inv[3]%mod*a[i]%mod;
79     build(1,1,n);
80     while (T--)
81     {
82         int x=ra(),val=ra();
83         change(1,x,n,(LL)val*inv[a[x]]%mod);
84         printf("%d\n",t[1].sum);
85         a[x]=val;
86     }
87     return 0;
88 }

 

转载于:https://www.cnblogs.com/ccd2333/p/6798451.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计中的实现,以及它们在MATLAB环境中的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用中颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述中提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法中,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用中,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值