CF 444B(DZY Loves FFT-时间复杂度)

本文介绍了一个关于快速傅立叶变换的应用挑战,其中涉及到随机序列的生成与特殊卷积运算的计算方法。通过使用FFT来优化计算过程,并提供了一种简单但有效的解题策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

B. DZY Loves FFT
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

DZY loves Fast Fourier Transformation, and he enjoys using it.

Fast Fourier Transformation is an algorithm used to calculate convolution. Specifically, if ab and c are sequences with length n, which are indexed from 0 to n - 1, and

We can calculate c fast using Fast Fourier Transformation.

DZY made a little change on this formula. Now

To make things easier, a is a permutation of integers from 1 to n, and b is a sequence only containing 0 and 1. Given a and b, DZY needs your help to calculate c.

Because he is naughty, DZY provides a special way to get a and b. What you need is only three integers ndx. After getting them, use the code below to generate a and b.

//x is 64-bit variable;
function getNextX() {
    x = (x * 37 + 10007) % 1000000007;
    return x;
}
function initAB() {
    for(i = 0; i < n; i = i + 1){
        a[i] = i + 1;
    }
    for(i = 0; i < n; i = i + 1){
        swap(a[i], a[getNextX() % (i + 1)]);
    }
    for(i = 0; i < n; i = i + 1){
        if (i < d)
            b[i] = 1;
        else
            b[i] = 0;
    }
    for(i = 0; i < n; i = i + 1){
        swap(b[i], b[getNextX() % (i + 1)]);
    }
}

Operation x % y denotes remainder after division x by y. Function swap(x, y) swaps two values x and y.

Input

The only line of input contains three space-separated integers n, d, x (1 ≤ d ≤ n ≤ 100000; 0 ≤ x ≤ 1000000006). Because DZY is naughty, x can't be equal to 27777500.

Output

Output n lines, the i-th line should contain an integer ci - 1.

Sample test(s)
input
3 1 1
output
1
3
2
input
5 4 2
output
2
2
4
5
5
input
5 4 3
output
5
5
5
5
4
Note

In the first sample, a is [1 3 2]b is [1 0 0], so c0 = max(1·1) = 1c1 = max(1·0, 3·1) = 3c2 = max(1·0, 3·0, 2·1) = 2.

In the second sample, a is [2 1 4 5 3]b is [1 1 1 0 1].

In the third sample, a is [5 2 1 4 3]b is [1 1 1 1 0].


这题解法‘朴素’得难以置信

转载自http://codeforces.com/blog/entry/12959

Firstly, you should notice that AB are given randomly.

Then there're many ways to solve this problem, I just introduce one of them.

This algorithm can get Ci one by one. Firstly, choose an s. Then check if Ci equals to n, n - 1, n - 2... n - s + 1. If none of is the answer, just calculate Ci by brute force.

The excepted time complexity to calculate Ci - 1 is around

where .

Just choose an s to make the formula as small as possible. The worst excepted number of operations is around tens of million.


对于每次询问:

先暴力枚举,看看答案在不在[n-s+1,n]中

否则暴力。

复杂度=O(s+(tot'0'/i)^s*tot'1')

(tot'0'/i)^s表示[n,n-s+1]中没有答案


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (100000+10)
#define MAXX (1000000006+1)
#define N_MAXX (27777500)
long long mul(long long a,long long b){return (a*b)%F;}
long long add(long long a,long long b){return (a+b)%F;}
long long sub(long long a,long long b){return (a-b+(a-b)/F*F+F)%F;}
typedef long long ll;
ll n,d,x;
int i,a[MAXN],b[MAXN];
//x is 64-bit variable;
ll getNextX() {
    x = (x * 37 + 10007) % 1000000007;
    return x;
}
void initAB() {
    for(i = 0; i < n; i = i + 1){
        a[i] = i + 1;
    }
    for(i = 0; i < n; i = i + 1){
        swap(a[i], a[getNextX() % (i + 1)]);
    }
    for(i = 0; i < n; i = i + 1){
        if (i < d)
            b[i] = 1;
        else
            b[i] = 0;
    }
    for(i = 0; i < n; i = i + 1){
        swap(b[i], b[getNextX() % (i + 1)]);
    }
}

int q[MAXN]={0},h[MAXN]={0};
int main()
{
//	freopen("FFT.in","r",stdin);
//	freopen("FFT.out","w",stdout);
	
	
	cin>>n>>d>>x;
	initAB();
	
	Rep(i,n) if (b[i]) q[++q[0]]=i;
	Rep(i,n) h[a[i]]=i;
	
//	Rep(i,n) cout<<a[i]<<' ';cout<<endl;
//	Rep(i,n) cout<<b[i]<<' ';cout<<endl;
	
	
	
	Rep(i,n)
	{
		int s=30,ans=0;
		Rep(j,30)
		{
			if (n-j<=0) break;
			int t=h[n-j];
			if (t<=i&&b[i-t]) {ans=n-j; break;} 
		}		
		if (!ans)
		{
			For(j,q[0])
			{
				int t=q[j];
				if (t>i) break;
				ans=max(ans,a[i-t]*b[t]);
			}
		}
		
		printf("%d\n",ans);
		
		
	}
	
	return 0;
}



<think>嗯,用户想了解如何优化二维差分算法以降低时间复杂度,防止超时。首先,我得回忆一下二维差分的基本原理。二维差分常用于矩阵的区间更新操作,比如给某个子矩阵的所有元素加上一个常数c。常规的二维差分方法是通过预处理差分数组,然后在更新时操作四个角点,这样每次更新的时间复杂度是O(1),而构建差分数组和最终还原原数组的时间复杂度是O(mn),其中m和n是矩阵的行数和列数。 用户提到的优化可能涉及到如何进一步减少常数因子或者其他优化技巧。不过根据常规的二维差分算法,时间复杂度已经是O(1)每次更新,这已经非常高效了。可能用户遇到的情况是,在多次查询的时候,或者数据量特别大的情况下,如何进一步优化。例如,在极端大规模的数据情况下,即使每次操作是O(1),但总时间可能还是不够,这时候可能需要考虑空间换时间,或者并行处理等方法。 另外,根据用户提供的参考引用[2],里面提到二维差分可以达到O(1)时间复杂度,所以可能用户的问题在于如何正确实现二维差分,避免在实现过程中引入更高的时间复杂度。例如,如果在每次更新时没有正确应用差分数组的四角操作,而是遍历了整个子矩阵,那么时间复杂度就会变成O(k^2)(k为子矩阵的大小),这显然会导致超时。 还有可能,用户在处理二维差分后的前缀和计算时,如果使用了低效的方法,比如每次都重新计算整个矩阵,而不是预先计算前缀和数组,那么时间复杂度也会增加。正确的做法应该是在所有更新操作完成后,一次性通过前缀和还原原矩阵,这样时间复杂度是O(mn),而不会每次查询都重复计算。 可能还需要考虑输入输出优化的问题,尤其是在处理大规模数据时,频繁的I/O操作可能导致超时。这时候,使用快速的输入输出方法,比如在Python中使用sys.stdin.readline代替input,或者在C++中使用scanf/printf而不是cin/cout,可能有助于减少运行时间。 另外,代码实现的细节也很重要。例如,在初始化差分数组时,是否正确地处理了边界条件,避免数组越界导致的错误,或者在更新时是否正确计算了四个角点的坐标。如果这些细节处理不当,可能需要额外的错误处理代码,从而增加时间开销。 还有一种情况是,当需要同时进行多次更新和查询时,是否能够将更新操作批量处理,最后统一进行前缀和计算,而不是每次查询都进行一次计算。这样可以减少前缀和计算的次数,从而降低总的时间复杂度。 总结来说,优化二维差分算法的主要方向包括:确保每次更新操作的时间复杂度确实是O(1),正确实现差分数组的四角更新;在预处理和最终计算前缀和时保持O(mn)时间复杂度;优化输入输出方法以减少I/O时间;处理边界条件以避免错误和额外开销;以及合理组织更新和查询的顺序,减少不必要的计算。</think>### 二维差分算法优化方法 二维差分算法的时间复杂度优化核心在于保持其$O(1)$的**单次区间更新效率**,并通过以下方法避免超时: --- #### 1. **差分数组的数学原理** 二维差分的核心公式为: $$ diff[i][j] = a[i][j] - a[i-1][j] - a[i][j-1] + a[i-1][j-1] $$ 通过四角坐标$(x1,y1)$和$(x2,y2)$进行区间更新: $$ diff[x1][y1] += c \\ diff[x1][y2+1] -= c \\ diff[x2+1][y1] -= c \\ diff[x2+1][y2+1] += c $$ 此操作始终保持单次更新时间复杂度为$O(1)$[^2]。 --- #### 2. **优化实现细节** - **边界条件处理** 设置差分数组大小为$(m+2) \times (n+2)$,避免越界判断的额外开销。 ```python diff = [[0]*(n+2) for _ in range(m+2)] ``` - **输入输出加速** 使用`sys.stdin.readline`代替标准输入函数(Python示例): ```python import sys input = sys.stdin.readline ``` --- #### 3. **批量操作与计算分离** - **先完成所有更新操作**,再通过**前缀和计算**一次性还原最终矩阵: ```python # 计算二维前缀和 for i in range(1, m+1): for j in range(1, n+1): diff[i][j] += diff[i-1][j] + diff[i][j-1] - diff[i-1][j-1] ``` 该步骤时间复杂度为$O(mn)$,与矩阵规模相关但**仅需执行一次**。 --- #### 4. **应用场景对比** | 方法 | 单次更新时间复杂度 | 空间复杂度 | 适用场景 | |--------------|---------------------|------------|--------------------------| | 暴力法 | $O(k^2)$ | $O(1)$ | 极小规模矩阵 | | 二维差分 | $O(1)$ | $O(mn)$ | 高频区间更新+低频查询 | --- #### 5. **实际代码示例(Python)** ```python def apply_diff(diff, m, n): # 计算前缀和还原矩阵 for i in range(1, m+1): for j in range(1, n+1): diff[i][j] += diff[i-1][j] + diff[i][j-1] - diff[i-1][j-1] return diff # 初始化 m, n = 5, 5 diff = [[0]*(n+2) for _ in range(m+2)] # 对子矩阵(2,2)-(4,4)加3 x1, y1, x2, y2, c = 2, 2, 4, 4, 3 diff[x1][y1] += c diff[x1][y2+1] -= c diff[x2+1][y1] -= c diff[x2+1][y2+1] += c # 最终计算 result = apply_diff(diff, m, n) ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值