• 19-11-07-~


    怕被喷,于是写个反思。

    ZJ:

    马上就结束了,不管是如何……如何……

    T1看看,写一个暴力,然后开始寻求规律,然后也没找出来。

    T2先码了一个大暴力,然后发现可以$Theta(N^2)$dp,然后有qj了一点分。

    T3先想的是把每一个MagicStone的贡献单独考虑,后来过不了大样例,发现错了,要容斥。

    于是去码暴力,最后没弄完。如果写完了就有$10$分

    没办法,就再补补吧。

    26
    Miemeng 30
    00:59:58
    50
    00:59:59
    0
    00:59:59
    80
    00:59:59

    终于有题解la:

    好!

    T1:

    大神秒切蒟蒻不会的题。

    $20\%$算法:

    直接归并即可。

    复杂度很高:$O(NM)$

    $100\%$算法:

    有两个做法法法法法法法法法法法法。

    法1:

    我们可以粘题解通过当前数的位置得到
    这个数在另一个序列的期望位置。假设当前的数为 $x$ ,期望位置的数
    为 $y$ ,下一个数为 $z$ ,那么 $z leq x leq y$ 时 $x$ 就是答案,否则比较一下大小,往两边跳。

    法2:

    首先我们考虑如何减小问题规模。

    我们想想暴力可以怎么搞。

    往一个数据结构里扔数,并维护$size$,如果正好为$k$,我们就把$k$输出来。

    那前面的呢?弃掉了。

    于是我们是不是可以通过弃掉前面的数来使后面的数正确呢?

    显然可以。

    于是我们考虑加速这个过程,一个一个弃不慢么

    那么分治的思想告诉我们要用中点以平衡复杂度。

    考虑两个区间$[l_a,r_a],[l_b,r_b]$的第$frac{k}{2}$个数

    如果$A_{k/2}<B_{k/2}$,那么$A_{k/2}$及之前的可以全部弃掉了。

    问题转换为在$[l_a+k/2+1,r_a],[l_b,r_b]$中找第$frac{k}{2}$个数,问题规模就缩小了一半。

    重复上述操作直到你去世可以一步出答案。

    $A_{k/2} geq B_{k/2}$同理。

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #define N 555555
    
    using namespace std;
    
    int pn,arr[N],brr[N],qn;
    
    int read() {
    	char c=getchar();
    	int x = 0;
    	for(;c<'0'||c>'9';c=getchar());
    	for(;c>='0'&&c<='9';c=getchar())x=x*10-'0'+c;
    	return x;
    }
    int solve(int kth,int l1,int r1,int l2,int r2){
    //	cout<<kth<<" "<<l1<<" "<<r1<<" "<<l2<<" "<<r2<<endl;
    	int hlf=kth/2;
    	if(l1>r1){
    		return brr[l2+kth-1];
    	}
    	else if(l2>r2){
    		return arr[l1+kth-1];
    	}
    	else if(kth == 1){
    		int ans=0x7fffffff;
    		if(l1<=r1) ans=min(ans,arr[l1]);
    		if(l2<=r2) ans=min(ans,brr[l2]);
    		return ans;
    	}
    	else if(l1+hlf-1<=r1 && l2+hlf-1<=r2) {
    		if(arr[l1+hlf-1] < brr[l2+hlf-1])
    			 return solve(kth-hlf,l1+hlf,r1,l2    ,r2);
    		else return solve(kth-hlf,l1    ,r1,l2+hlf,r2);
    	}
    	else if(l1+hlf-1<=r1){
    		return solve(kth-hlf,l1+hlf,r1,l2,r2);
    	}
    	else if(l2+hlf-1<=r2){
    		return solve(kth-hlf,l1,r1,l2+hlf,r2);
    	}
    	else {
    		puts("µ");
    		return 0;
    	}
    }
    
    int main(){
    #ifndef LOCAL
    	freopen("median.in" ,"r",stdin);
    	freopen("median.out","w",stdout);
    #endif
    	int opt,a,b,c,d;
    	pn=read();qn=read();
    	for(int i=1;i<=pn;i++)
    		arr[i]=read();
    	for(int i=1;i<=pn;i++)
    		brr[i]=read();
    	for(int i=1;i<=qn;i++){
    		opt=read();
    		if(opt==1){
    			a=read(),b=read(),c=read();
    			if(a==0) arr[b]=c;
    			else     brr[b]=c;
    		}
    		else{
    			a=read(),b=read(),c=read(),d=read();
    			int k=(b-a+d-c+2+1)/2;
    			printf("%d
    ",solve(k,a,b,c,d));
    		}
    	}
    }
    

    T2:

    %%%toot

    上面的大聚聚暴锤正解。

    正解:线段树维护单调栈。复杂度:$Theta(N log N)$

    巨解:单调栈自己维护自己。复杂度:$Theta(N)$

    于是……

    首先我们知道如何写暴力$dp$。

    //min
    
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #define N 222222
    #define LL long long
    
    using namespace std;
    
    int pn;
    int arr[N];
    int a,b,c,d;
    LL dp[N];
    
    LL f(LL x){
    	return x*x*x*a+x*x*b+x*c+d;
    }
    LL ans=0;
    namespace qj{
    	void work(){
    		bool is_upd=0;
    		LL minn=0x7fffffff;
    		for(int i=1;i<=pn;i++){
    			minn=min(1ll*arr[i],minn);
    			if(f(arr[i])>0){
    				is_upd=1;
    				ans+=f(arr[i]);
    			}
    		}
    		if(!is_upd){
    			ans=f(minn);
    		}
    		cout<<ans<<endl;
    	}
    }
    int main(){
    #ifndef LOCAL
    	freopen("min.in" ,"r",stdin);
    	freopen("min.out","w",stdout);
    #endif
    	ios_base::sync_with_stdio(false);
    	cin>>pn>>a>>b>>c>>d;
    	for(int i=1;i<=pn;i++)
    		cin>>arr[i];
    	if(a==0 && b==0 && c<=0 ){
    		qj::work();
    		return 0;
    	}
    	LL minn=0x7fffffff;
    	for(int i=1;i<=pn;i++){
    		minn=min(minn,1ll*arr[i]);
    		dp[i]=f(minn);
    	}
    	for(int i=1;i<=pn;i++){
    		minn=0x7fffffff;
    		for(int j=i+1;j<=pn;j++){
    			minn=min(minn,1ll*arr[j]);
    			dp[j]=max(dp[j],dp[i]+f(minn));
    		}
    	}
    	cout<<dp[pn]<<endl;
    }
    

    于是我们考虑如何优化$dp$过程

    方法1:

    $k$常优化。

    一般遇到这种题出题人都$kuku$,

    我们把第二层循环搞一搞,让它只跑$k$次

    复杂度$Theta(kN)$。

    你可以试试$300 sim 500$

    方法2:

    单调栈,因为我们要维护区间最小值于是考虑这个数据结构。

    我们发现单调栈一段区间内的最小值是一定的。

    于是先维护最小值,

    然后$dp$一定从这段区间内的最大dp值转移过来。

    于是维护每个区间的最大$dp+f(min{l,r})$

    那么我们就会被题解蛊惑用线段树

    但是聚聚没有。

    发现每次单调栈都只是把后面的删掉,或是加入。

    我们直接在单调栈里维护前缀最大值直接转移就好了。

    ××我也不知道大聚聚怎么想到的,我太蒟蒻了$QAQ$

    #include <iostream>
    #include <cstring>
    #include <climits>
    #include <cstdio>
    #include <stack>
    #define N 222222
    #define LL long long
    
    using namespace std;
    
    struct Mystack{
    	LL A[2*N];
    	int tp;
    	Mystack(){tp=0;}
    	void pop(){tp--;}
    	void push(const LL k){A[tp++]=k;}
    	void clear(){tp=0;}
    	int size(){return tp;}
    	LL top(){return A[tp-1];}
    	bool empty(){return tp==0;}
    }st,ddp,premax;
    int pn;
    LL arr[N];
    LL dp[N];
    LL a,b,c,d;
    inline LL f(LL x){
    	return x*x*x*a+x*x*b+x*c+d;
    }
    int main(){
    #ifndef LOCAL
    	freopen("min.in" ,"r",stdin);
    	freopen("min.out","w",stdout);
    #endif
    	ios_base::sync_with_stdio(false);
    	cin>>pn>>a>>b>>c>>d;
    	for(int i=1;i<=pn;i++)
    		cin>>arr[i];
    	dp[0]=0,arr[0]=-1e16;
    	st.push(0);
    	ddp.push(arr[0]);
    	premax.push(arr[0]);
    	for(int i=1;i<=pn;i++){
    //		cout<<i<<" "<<dp[i-1]<<endl;
    		LL pdp=dp[i-1];
    		while(!st.empty() && arr[st.top()]>=arr[i]){
    			pdp=max(pdp,ddp.top());
    			st.pop();
    			ddp.pop();
    			premax.pop();
    		}
    		dp[i]=max(1ll*pdp+f(arr[i]),premax.top());
    		st.push(i);
    		ddp.push(pdp);
    		premax.push(max(premax.top(),pdp+f(arr[i])));
    	}
    	cout<<dp[pn]<<endl;
    }
    

    T3不会

  • 相关阅读:
    python笔记——调试和异常处理
    [算法学习] 线段树,树状数组,数堆,笛卡尔树
    【cpp】G++中不支持static_cast?
    【生活感想】不够淡定
    数值线性代数小结
    伪逆
    统计机器学习
    Numerical Methods with MATLAB(1)
    吐槽iOS国际化:关于NSLocalizedString的使用
    iOS 沙盒路径操作:新建/删除文件和文件夹
  • 原文地址:https://www.cnblogs.com/kalginamiemeng/p/Exam20191107.html
Copyright © 2020-2023  润新知