• #优化枚举#洛谷 2119 魔法阵


    题目


    分析

    首先显然与物品数量无关,用一个桶记录每个数的出现次数即可
    题目的数据随机告诉我们(O(n^2))的算法可能能够卡过去,但显然要找一些更优的算法
    然后研究一下性质,发现(x_b-x_a)出现了两次,那存不存在一个量可以尽量表达(x_a,x_b,x_c,x_d)
    考虑枚举(t=x_d-x_c),因为它是(x_b-x_a)(frac{1}{2})倍,所需要枚举的范围可能会更小
    那么(x_b-x_a=2t,x_c-x_b>6t),那我枚举的(t)只需要在((n-1)/9)内就行了
    那肯定还要枚举一个数,由于(x_c-x_b)不能完全确定,不妨分成两种情况:

    1. 当枚举(x_a)时,求(x_a)(x_b)的方案数,那(x_c)(x_d)其实可以用后缀和表示
    2. 当枚举(x_d)时,求(x_c)(x_d)的方案数,那(x_a)(x_b)其实可以用前缀和表示

    时间复杂度(O(frac{1}{9}n^2)),实际上常数非常小


    代码

    #include <cstdio>
    #include <cctype> 
    #define rr register
    using namespace std;
    const int N=40011;
    int m,n,a[N],c[N],ans[4][N];
    inline signed iut(){
    	rr int ans=0; rr char c=getchar();
    	while (!isdigit(c)) c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans; 
    }
    inline void print(int ans){
    	if (ans>9) print(ans/10);
    	putchar(ans%10+48);
    }
    signed main(){
    	m=iut(); n=iut();
    	for (rr int i=1;i<=n;++i) ++c[a[i]=iut()];
    	for (rr int i=1;i*9<m;++i){
    		for (rr int D=9*i+2,s=0;D<=m;++D){
    			rr int C=D-i,B=C-6*i-1,A=B-2*i;
    			s+=c[A]*c[B],ans[2][C]+=c[D]*s,ans[3][D]+=c[C]*s;
    		}
    		for (rr int A=m-9*i-1,s=0;A;--A){
    			rr int B=A+2*i,C=B+6*i+1,D=C+i;
    			s+=c[C]*c[D],ans[0][A]+=c[B]*s,ans[1][B]+=c[A]*s;
    		}
    	}
    	for (rr int i=1;i<=n;++i)
    	    for (rr int j=0;j<4;++j)
    	        print(ans[j][a[i]]),putchar(j==3?10:32);
    	return 0;
    }
    
  • 相关阅读:
    海龟交易
    暑假攻略:怎样让孩子过一个充实又省钱的假期
    值得追随
    在哪里能找的你想要的答案?
    顺势加仓策略
    交易中 你的加仓策略是怎样的?背后的逻辑是什么?
    驻守深寒:寻找那些有效地关键K线
    统计相关
    求助Ubuntu16.10如何设置默认启动为字符界面
    【Linux系列】Ubuntu ping通,xshell无法连接
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/13776238.html
Copyright © 2020-2023  润新知