前缀和(presum)算法预处理

2024-03-25

坐标变换(其二)

  • 关于math函数的使用:如何使用π——使用acos(-1)函数求的π值
  • cout«如何输出保持小数位数——cout << fixed << setprecision(3)
  • double数如何取模——fmod(被除数,除数)函数(没用的操作,但至少掌握一个函数)

80分代码:

一开始的思路是将输入都存起来,根据i,j去遍历,k相乘得到sum_k,$\theta$相加得到sum_$\theta$,然后使用fmod函数取模2π,但是超时80分

$\theta$相加得到sum_$\theta$ 看似简化,其实鸟用没有,直接cos也是一样的复杂度,你还多一个取模的操作,更慢了

唯一优化的点就在于:在i->j的遍历上,如何快速一次性查询——联想前缀和(连续子串)

#include<bits/stdc++.h> 
using namespace std;

int main(){
	int n,m;
	cin>>n>>m;
	vector<pair<int,double>> op;
	while(n--){
		int a;
		double b;
		cin>>a>>b; 
		pair<int,double> temp = make_pair(a,b);
		op.push_back(temp);
	}
	double sum_k,sum_th;
	while(m--){
		int i,j,x,y;
		cin>>i>>j>>x>>y;
		i-=1;j-=1;
		sum_k=1;sum_th=0;
		for(int idx=i;idx<=j;++idx){
			pair<int,double> temp_op = op[idx];
			if(temp_op.first==1){
				sum_k*=temp_op.second;//记录累计K
			}else{
				sum_th+=temp_op.second; //记录累计r
			}
		}
		sum_th = fmod(sum_th, 2 * acos(-1));//以为自己聪明能降时间,其实没鸟用
		cout << fixed << setprecision(3)<<sum_k*x*cos(sum_th)-sum_k*y*sin(sum_th)<<" "<<sum_k*x*sin(sum_th)+sum_k*y*cos(sum_th)<<endl;
	}
	return 0;
}

100分(前缀和):

  1. 维护一个前缀和数组,存储从0到目前为止累计的缩放k与旋转角r
  2. 当计算从begin到end时,利用前缀和性质快速求解
#include<bits/stdc++.h> 
using namespace std;

int main(){
	int n,m;
	cin>>n>>m;
	vector<pair<double,double>> sum;//维护一个前缀和数组,存储从0到目前为止累计的k与r
	int idx=1;
	sum.push_back({1,0});//小trick,在下标0处手动添加元素,后面处理时不用特殊判断处理下标0
	int flag;double op;
	while(n--){
		cin>>flag>>op;
		if(flag==1) {
			sum.push_back({sum[idx-1].first*op,sum[idx-1].second});
		}else{
			sum.push_back({sum[idx-1].first,sum[idx-1].second+op});
		}
		idx++;
	}
	while(m--){
		int begin,end,x,y;
		cin>>begin>>end>>x>>y;
		double k = sum[end].first/sum[begin-1].first;//当计算从begin到end时,利用前缀和性质快速求解
		double r = sum[end].second-sum[begin-1].second;
		cout << fixed << setprecision(3)<<k*x*cos(r)-k*y*sin(r)<<" "<<k*x*sin(r)+k*y*cos(r)<<endl;
	}
	return 0;
}