题解:AT_agc051_e [AGC051E] Middle Point
Solution
有人往 NOI 模拟赛 T1 放这个。
祝搬题人和他的家人们身体健康,万事如意,天天开心!
定义有理数
本质上给你若干个向量(凸包上的),然后求这些凸包的线性组合,要求系数和
凸包边界上的情况是容易处理的,考虑内部的点。内部的整点当然可以直接 pick 定理算,但是显然不是所有的整点都能构造到。
有结论:我们将一个向量移动到
合法有理数关于
所有
合法有理数关于
如果
这样坐标变换之后变成求凸包内整点个数。上面已经提到了可以用 pick 定理直接算。
大家觉得这个适合放在 T1 吗。
#include<bits/stdc++.h>
#define int long long
#define ffor(i,a,b) for(int i=(a);i<=(b);i++)
#define roff(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int MAXN=100+10;
int n,x[MAXN],y[MAXN],tot=0,ans;
struct Node {__int128 x,y;}st[MAXN*2],nst[MAXN*2];
Node A;
__int128 B;
__int128 dabs(__int128 v) {
return (v>=0)?v:-v;
}
__int128 calc(Node A,Node B,Node C) {
__int128 x=B.x-A.x,y=B.y-A.y;
__int128 X=C.x-A.x,Y=C.y-A.y;
return dabs(X*y-x*Y);
}
signed main() {
freopen("aka.in","r",stdin);
freopen("aka.out","w",stdout);
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n;
ffor(i,1,n) cin>>x[i]>>y[i];
vector<pair<int,int>> vc;
ffor(i,1,n) vc.push_back({x[i],y[i]});
sort(vc.begin(),vc.end());
ffor(i,1,n) x[i]=vc[i-1].first,y[i]=vc[i-1].second;
int lst=1;
ffor(i,1,n) {
while(tot>lst&&(y[i]-st[tot].y)*(st[tot].x-st[tot-1].x)>(st[tot].y-st[tot-1].y)*(x[i]-st[tot].x)) --tot;
st[++tot]={x[i],y[i]};
}
roff(i,n-1,1) {
while(tot>lst&&(y[i]-st[tot].y)*(st[tot].x-st[tot-1].x)>(st[tot].y-st[tot-1].y)*(x[i]-st[tot].x)) --tot;
st[++tot]={x[i],y[i]};
}
ffor(i,1,tot-1) {
__int128 dt=__gcd(dabs(st[i].x-st[i+1].x),dabs(st[i].y-st[i+1].y));
ans+=dt&-dt;
}
__int128 sx=st[1].x,sy=st[1].y;
A={x[2]-sx,y[2]-sy};
ffor(i,3,n) {
Node AA={x[i]-sx,y[i]-sy};
while(A.x&&AA.x) {
__int128 del=A.x/AA.x;
A.x-=AA.x*del,A.y-=AA.y*del;
swap(A,AA);
}
if(AA.x) swap(A,AA);
B=__gcd(B,dabs(AA.y));
}
if(B) B/=(B&-B);
while(1) {
while(A.x%2==0&&A.y%2==0) A.x/=2,A.y/=2;
if(A.x%2) break ;
if(B) A.y+=B;
else break ;
}
ffor(i,1,tot) {
__int128 nx=(st[i].x-st[1].x),ny=(st[i].y-st[1].y);
nst[i].x=nx/A.x;
ny-=(nx/A.x)*A.y;
if(ny) nst[i].y=ny/B;
}
__int128 S=0;
ffor(i,2,tot-2) S+=calc(nst[1],nst[i],nst[i+1]);
S=S+2;
ffor(i,1,tot-1) S-=__gcd(dabs(nst[i+1].x-nst[i].x),dabs(nst[i+1].y-nst[i].y));
cout<<(int)(S/2+ans);
return 0;
}