• LOJ#6065. 「2017 山东一轮集训 Day3」第一题 题解


    题目链接

    枚举 (Theta(n)) 种正方形的边长 (L) , 不难发现在选的 (6) 条边中只可能有 (2) 条 / (3) 条 边的长度为 (L) .

    (2) 条边长为 (L) :

    另外两条边分别由两个比 (L) 小的数拼接而成。枚举拼成 L 的方式 ( 即 (L = x + y)((x leq y))(x)(y) ) , 不难发现每种方式之间相互独立,然后分别考虑一下只用这种方式 / 使用两种不同方式 的方案数并求和即可。

    (3) 条边长为 (L) :

    剩下的一条边由三个加起来 (=L) 的数字拼接而成,不妨设 (L = x + y + z(xleq yleq z)) , 先 (Theta(n)) 处理 (x = y = z) 或者 (x = y < z) 或者 (x < y = z) 的三种情况。

    最后 (x < y < z) , 枚举 z 之后变成查询前 (i) 种数拼成 (L-z) 的方案数 , 这个可以离线下来做。

    (Theta(n^2))

    code :

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    template <typename T> void read(T &x){
    	static char ch; x = 0,ch = getchar();
    	while (!isdigit(ch)) ch = getchar();
    	while (isdigit(ch)) x = x * 10 + ch - '0',ch = getchar();
    }
    const int N = 5005,M = 10000005<<1;
    int id[M],cnt[M],n,a[N],m,b[N]; LL c[N],c2[N],c3[N],c4[N],ans;
    inline LL calc1(int x){
    	LL ans = 0,s = 0; register int now,i,j;
    	for (i = 1; i <= m && b[i] <= x>>1; ++i) if (j = id[x-b[i]]){
    		if (i == j) now = c2[i],ans += c4[i];
    		else now = c[i] * c[j],ans += c2[i] * c2[j];
    		ans += s * now,s += now;
    	}
    	return ans;
    }
    inline LL calc2(int x){
    	LL ans = 0; register int i,j;
    	if (x % 3 == 0) ans += c3[id[x/3]];
    	for (i = 1; i <= m && b[i] < x; ++i)
    		if ((b[i]<<1) <= x && (j = id[x-(b[i]<<1)]) && b[j] != b[i]) ans += c[j] * c2[i];
    	return ans;
    }
    int main(){
    	register int i,j;
    	read(n);
    	for (i = 1; i <= n; ++i) read(a[i]); sort(a+1,a+n+1);
    	for (i = 1; i <= n; ++i) if (i == 1 || a[i] != a[i-1]) b[++m] = a[i];
    	for (i = 1; i <= m; ++i) id[b[i]] = i;
    	for (i = 1; i <= n; ++i) ++c[id[a[i]]];
    	for (i = 1; i <= m; ++i) c2[i] = c[i] * (c[i]-1) / 2,c3[i] = (LL)c[i] * (c[i]-1) * (c[i]-2) / 6,c4[i] = (LL)c[i] * (c[i]-1) * (c[i]-2) * (c[i]-3) / 24; 
    	for (i = 1; i <= m; ++i) if (c[i] >= 2) ans += c2[i] * calc1(b[i]);
    	for (i = 1; i <= m; ++i) if (c[i] >= 3) ans += c3[i] * calc2(b[i]);
    	for (i = 1; i < m-1; ++i){
    		for (j = 1; j < i; ++j) cnt[b[j] + b[i]] += c[i] * c[j];
    		for (j = i+2; j <= m; ++j) ans += c3[j] * cnt[b[j]-b[i+1]] * c[i+1];
    	}
    	cout << ans << '
    '; 
    	return 0;
    }
    
  • 相关阅读:
    linux下查看jdk路径
    mysql内部级联删除
    Mybatis Mapper.java和Mapper.xml能否分离问题
    The request sent by the client was syntactically incorrect问题解决
    centos下-MariaDB的安装
    对于mariadb安装后可以默认使用无密码登录的问题解决方案
    C#复习笔记(2)--C#1所搭建的核心基础
    C#精粹--协变和逆变
    linux和sqlserver 2017的安装
    C#精粹--闭包陷阱
  • 原文地址:https://www.cnblogs.com/s-r-f/p/13746405.html
Copyright © 2020-2023  润新知