结题思路如下:
记一个长方向水平方向宽度为h,竖直方向宽度为w,对n类长方形先按h排序,再按w排序,并将所有h相同的长方形放到一个容器中。可知,h不同的每个容器,代表着所拼接成的大长方形的一列或者是几列。
对每个容器,如果一种w出现在一个容器中,则必然出现在其他所有容器中,且该中w的数目与该容器所有长方形数目的比值,与其他容器相应的比值相同。即任意一个容器的一类长度为w的长方形在其容器所在列所占行数与其它容器相同。
对每个容器求其所有w类型所占个数的gcd,该值记为gcdi,那么只考虑这个容器,能拼接出最少的行数为 min_rowi = sumi / gcdi. 然后对所有的min_rowi求最小公倍数得到min_row. 若对所有的sumi,有sumi % min_row == 0 ,那么此时min_row 就是能够考虑所有容器下的能拼出的最小行数。
因为sum i / min_rowi = gcdi ,若 再有 sum % min_row == 0 则有 sum / min_row 为 gcdi的因子,从而该容器可以拼出min_row 行 .
对于所有sumi % min_row == 0 只需要所有的 sumi的gcd(记为max_row) % min_row == 0 就可以了.
最后的枚举min_row 到 max_row之间所有的可行列方式需要注意技巧,只需做sqrt(max_row)次枚举即可。只要比sqrt(max_row)大的 max_row的因子X,必然可以在美剧 max_row / x 时,同时处理。
排序注意 时注意 return x != rhs.x ? x < rhs.x : y < rhs.y。(不等号)
#include<bits/stdc++.h>
using namespace std;
#define mp make_pair
typedef long long ll;
typedef long double ld;
const int maxn = 205000;
vector<pair<ll,ll>> st[maxn];
int m = 0 , n ;
ll cnt[maxn];
struct node{
ll h,w,num;
bool operator<(const node& rhs)const{
return h != rhs.h ? h < rhs.h : w < rhs.w;
}
}a[maxn];
ll least_common_mutiple(ll x , ll y){
ll temp = __gcd(x , y);
return x / temp * y;
}
ll min_row =1;
ll max_row;
void read(){
cin>>n;
ll preh;
for(int i=0;i<n;i++)
scanf("%I64d %I64d %I64d",&a[i].h,&a[i].w,&a[i].num);
sort(a,a+n);
for(int i=0;i<n;i++) {
if(i==0 || preh != a[i].h){
preh = a[i].h; ++m;
}
st[m].push_back(mp(a[i].w,a[i].num)),cnt[m]+=a[i].num;
}
max_row = cnt[1];
for(int i=2;i<=m;i++)
max_row = __gcd(max_row , cnt[i]);
}
bool judge(){
for(int i=1;i<=m;i++){
if(st[i].size() != st[1].size()) return false;
}
for(int i=1;i<=m;i++){
for(int j=0;j<st[i].size();j++){
if(st[i][j].first != st[1][j].first) return false;
if((ld)st[i][j].second / (ld) cnt[i] != (ld)st[1][j].second / (ld) cnt[1]) return false;
}
}
for(int i=1;i<=m;i++){
ll tt = st[i][0].second;
for(int j=0;j<st[i].size();j++){
tt = __gcd(st[i][j].second , tt);
}
tt = cnt[i] / tt;
min_row = least_common_mutiple(min_row , tt);
}
if(max_row >= min_row && max_row % min_row == 0) return true;
else return false;
}
void cal(){
int ans = 0;
for(ll i =1 ; i*i <=max_row ; i++){
if( i % min_row == 0 && max_row % i == 0)
ans++;
if(i * i != max_row && max_row % i == 0) {
ll ti = max_row / i;
if(ti % min_row == 0 && max_row % ti == 0)
ans++;
}
}
cout<<ans<<endl;
}
int main()
{
read();
if(judge()) cal();
else {
cout<<"0";
}
return 0;
}
/*
4
4 1 1
1 1 1
4 3 1
1 3 1
*/