1 条题解

  • 0
    @ 2025-11-27 11:01:03

    题意回顾

    我们需要计算在 X×YX \times Y 的整数格点范围内,满足以下条件的凸多边形个数:

    1. 顶点为整点 (xi,yi)(x_i,y_i),且 1xiX,1yiY1 \le x_i \le X, 1 \le y_i \le Y
    2. 多边形的任意一条边(不包含端点)不经过格点。
    3. 每条边的长度 K\le K 且为整数。
    4. 凸多边形,不退化(无三点共线、无 180180^\circ 角)。
    5. 输出结果对 2322^{32} 取模。

    数据范围:1X,Y1091 \le X,Y \le 10^91K2501 \le K \le 250


    关键转化

    1. 边不经过格点的条件

    边向量 (dx,dy)(dx, dy) 必须满足 gcd(dx,dy)=1\gcd(|dx|,|dy|) = 1(即本原向量)。

    2. 边长为整数的条件

    dx2+dy2dx^2 + dy^2 必须是完全平方数,且 K2\le K^2

    3. 凸多边形的向量表示

    凸多边形可以看作按极角递增的边向量序列 v1,v2,,vmv_1, v_2, \dots, v_m 满足:

    • 向量和 =(0,0)= (0,0)(闭合)
    • 相邻向量极角严格递增(保证凸且不退化)
    • 所有向量来自满足上述条件的本原向量集合

    算法步骤

    步骤 1:生成所有合法边向量

    枚举 dx=KKdx = -K \dots Kdy=KKdy = -K \dots K,满足:

    • gcd(dx,dy)=1\gcd(|dx|,|dy|) = 1
    • dx2+dy2K2dx^2 + dy^2 \le K^2
    • dx2+dy2\sqrt{dx^2 + dy^2} 为整数(即 dx2+dy2dx^2 + dy^2 是完全平方数)
    • 排除零向量

    记这些向量集合为 VV,大小 M=O(K2)M = O(K^2),实际 K250K \le 250 时约几百个。

    步骤 2:极角排序

    VV 中向量按极角(atan2(dy,dx)\mathrm{atan2}(dy,dx))排序,便于后续 DP。

    步骤 3:动态规划计数

    定义 DP 状态:

    • $dp[s][\text{sumX}][\text{sumY}][\text{minX}][\text{minY}][\text{maxX}][\text{maxY}]$ 表示:
      • 已选 ss 条边
      • 当前向量和 =(sumX,sumY)= (\text{sumX}, \text{sumY})
      • 坐标范围:x[minX,maxX]x \in [\text{minX}, \text{maxX}]y[minY,maxY]y \in [\text{minY}, \text{maxY}]

    但这样状态太大,需要优化。

    优化思路

    • 我们只关心最终 sumX=sumY=0\text{sumX} = \text{sumY} = 0 的序列
    • 坐标范围可以通过 minX=maxNegX\text{minX} = -\text{maxNegX} 等方式压缩
    • 实际实现时,可以固定起点在原点,最后乘以平移方案数

    步骤 4:平移方案计算

    对于一个向量序列,设:

    • Δxmax=max(prefixSumX)\Delta x_{\max} = \max(\text{prefixSumX})Δxmin=min(prefixSumX)\Delta x_{\min} = \min(\text{prefixSumX})
    • Δymax=max(prefixSumY)\Delta y_{\max} = \max(\text{prefixSumY})Δymin=min(prefixSumY)\Delta y_{\min} = \min(\text{prefixSumY})

    则需要的宽度 W=ΔxmaxΔxmin+1W = \Delta x_{\max} - \Delta x_{\min} + 1,高度 H=ΔymaxΔymin+1H = \Delta y_{\max} - \Delta y_{\min} + 1

    平移方案数 = max(0,XW+1)×max(0,YH+1)\max(0, X - W + 1) \times \max(0, Y - H + 1)

    步骤 5:最终计数

    对每个长度 m3m \ge 3 的合法向量序列(极角递增、和为零、相邻不共线),加上其平移方案数。


    2322^{32} 的处理

    由于模数是 2322^{32},可以用 unsigned int 自然溢出,或者用 uint64_t 计算后取模。


    复杂度分析

    • 向量数量 MO(K2)M \approx O(K^2)
    • DP 状态数与 MMKK 相关,实际可运行
    • 对于 K250K \le 250,经过优化的 DP 可以接受

    代码框架(伪代码)

    #include <bits/stdc++.h>
    using namespace std;
    using uint = unsigned int;
    
    int X, Y, K;
    uint mod = 1ULL << 32;
    
    struct Vec {
        int dx, dy;
        double angle;
        bool operator<(const Vec& other) const {
            return angle < other.angle;
        }
    };
    
    vector<Vec> vecs;
    
    void generate_vectors() {
        for (int dx = -K; dx <= K; dx++) {
            for (int dy = -K; dy <= K; dy++) {
                if (dx == 0 && dy == 0) continue;
                int len2 = dx*dx + dy*dy;
                if (len2 > K*K) continue;
                int len = sqrt(len2);
                if (len*len != len2) continue;
                if (gcd(abs(dx), abs(dy)) != 1) continue;
                vecs.push_back({dx, dy, atan2(dy, dx)});
            }
        }
        sort(vecs.begin(), vecs.end());
    }
    
    uint solve() {
        generate_vectors();
        int M = vecs.size();
        
        // DP 初始化及转移
        // 这里省略具体 DP 实现,它涉及多维状态
        
        uint ans = 0;
        // 对每个合法序列计算平移方案并累加
        return ans;
    }
    
    int main() {
        cin >> X >> Y >> K;
        cout << solve() << endl;
        return 0;
    }
    

    总结

    本题是一道结合计算几何、数论和动态规划的计数题,关键点在于:

    1. 将凸多边形条件转化为极角递增的本原向量序列
    2. 利用 gcd\gcd 和完全平方数条件筛选合法边向量
    3. 通过 DP 统计合法序列,并计算平移方案数
    4. 处理大范围 X,YX,Y 时只需知道坐标跨度
    • 1

    信息

    ID
    5640
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者