hdu 1496 Equaions 题解(数论,map)

本文介绍了一种高效解决四元二次方程问题的方法,通过优化算法将复杂度从四层循环降低至O(100^2),利用自定义Map结构避免log开销,实现快速求解。

原链接:
点我QωQ

题意简述

多组数据,每次给定 a , b , c , d a,b,c,d a,b,c,d,求有多少 x 1 , x 2 , x 3 , x 4 x1,x2,x3,x4 x1,x2,x3,x4满足 a x 1 2 + b x 2 2 + c x 3 2 + d x 4 2 = 0 ax1^2+bx2^2+cx3^2+dx4^2=0 ax12+bx22+cx32+dx42=0。保证 a , b , c , d a,b,c,d a,b,c,d [ − 50 , 50 ] [-50,50] [50,50]范围内,求的 x 1 , x 2 , x 3 , x 4 x1,x2,x3,x4 x1,x2,x3,x4要在 [ − 100 , 100 ] [-100,100] [100,100]的计数。

数据

输入

多组数据,读入到文件尾。每组数据包含四个正整数 a , b , c , d a,b,c,d a,b,c,d,在 [ − 50 , 50 ] [-50,50] [50,50]范围内。(即 &gt; = − 50 , &lt; = 50 &gt;=-50,&lt;=50 >=50,<=50)。

输出

有多少 x 1 , x 2 , x 3 , x 4 x1,x2,x3,x4 x1,x2,x3,x4满足条件并且 − 100 &lt; = x 1 , x 2 , x 3 , x 4 &lt; = 100 -100&lt;=x1,x2,x3,x4&lt;=100 100<=x1,x2,x3,x4<=100

样例

输入
1 2 3 -4
1 1 1 1
输出
39088
0

思路

显然四层循环是过不去的。。。经过实践,三层也是过不去的。。。必须要 O ( 10 0 2 ) O(100^2) O(1002)
才能过,带 l o g log log都不行。。。

但是我们要先能把四层循环写出来。代码:

int ans=0;
for(int x1=-100;x1<=100;++x1)
{
    for(int x2=-100;x2<=100;++x2)
    {
        for(int x3=-100;x3<=100;++x3)
        {
            for(int x4=-100;x4<=100;++x4)
            {
                if (x1*x1*a+x2*x2*b+x3*x3*c+x4*x4*d==0)
                {
                    ++ans;
                }
            }
        }
    }
}

我们对这个代码作一些变形:

int ans=0;
for(int x1=-100;x1<=100;++x1)
{
    for(int x2=-100;x2<=100;++x2)
    {
        for(int x3=-100;x3<=100;++x3)
        {
            for(int x4=-100;x4<=100;++x4)
            {
                if (x3*x3*c+x4*x4*d==-(x1*x1*a+x2*x2*b))
                {
                    ++ans;
                }
            }
        }
    }
}

你会发现我只是移项了一下。。。
但是这样之后就能想出一个优化了。我们会发现,后面两层循环相当于求有多少 x 3 , x 4 x3,x4 x3,x4满足 c x 3 2 + d x 4 2 = − ( a x 1 2 + b x 2 2 ) cx3^2+dx4^2=-(ax1^2+bx2^2) cx32+dx42=(ax12+bx22)。然后这个东西我们珂以用一个 m a p map map记录出来。我们会轻易想到用 S T L STL STL m a p map map做。但是我没这么做,因为经过计算,会 T L E 。 。 。 TLE。。。 TLE(不是带一个特别大的 l o g log log么。。。)

想想优化。 S T L STL STL m a p map map带一个 l o g log log,但是我们其实并不需要带 l o g log log。我们能求出来的最小值是 10 0 2 × − 50 100^2\times -50 1002×50,即 − 5 × 1 0 5 -5\times10^5 5×105。我们只要开一个长度为 2 × 1 0 6 2\times 10^6 2×106的数组,整个往右滚动 1 0 6 10^6 106位,就都珂以变成正下标了,直接上数组。在清空的时候,也不要直接 m e m s e t memset memset,而是反向进行计算的操作( + + + − - ),这样就珂以保证任何计算都是 O ( 10 0 2 ) O(100^2) O(1002)的了,也就珂以过了。

代码:

#include<bits/stdc++.h>
using namespace std;
namespace Flandle_Scarlet
{
    #define int long long
    #define N 1001000
    struct Map//更快的Map(不带log)
    {
        int v[(N<<1)+100];
        void clear()
        {
            memset(v,0,sizeof(v));
        }
        int& operator[](int i)//重载[]运算符
        {
            return *(v+i+N);
            //取值的时候向右滚动
        }
    };
    Map rec2;
    //rec2[i]表示x3*x3*c+x4*x4*d==i的有多少
    int a,b;
    int c,d;
    void Build()
    {
        for(int i=-100;i<=100;++i)
        {
            for(int j=-100;j<=100;++j)
            {
                if (i and j)//都不能是0
                {
                    ++rec2[i*i*c+j*j*d];
                }
            }
        }
    }

    void Solve()
    {
        int ans=0;
        for(int i=-100;i<=100;++i)
        {
            for(int j=-100;j<=100;++j)
            {
                if (i and j)
                {
                    ans+=rec2[-(i*i*a+j*j*b)];
                    //记录答案
                }
            }
        }
        printf("%lld\n",ans);
    }

    void Clear()
    {
        for(int i=-100;i<=100;++i)
        {
            for(int j=-100;j<=100;++j)
            {
                if (i and j)
                {
                    rec2[i*i*c+j*j*d]--;
                    //清空
                }
            }
        }
    }
    void Main()
    {
        if (0)
        {
            freopen("","r",stdin);
            freopen("","w",stdout);
        }
        while(scanf("%lld%lld%lld%lld",&a,&b,&c,&d)==4)
        {
            Build();
            Solve();
            Clear();
        }
    }
    #undef int //long long
};
int main()
{
    Flandle_Scarlet::Main();
    return 0;
}

回到总题解界面

### HDU 1072 C++ 实现解析 HDU 1072 是一个经典的动态规划问目名称为 **Catch That Cow**。该问的核心在于通过广度优先搜索 (BFS) 来寻找从起点到终点的最短路径步数。 #### 目描述 给定两个整数 `K` 和 `N`,表示农夫的位置和奶牛的目标位置。农夫可以通过三种方式移动: - 走一步到达 `K + 1` - 走一步到达 `K - 1` - 瞬间传送到 `2 * K` 目标是最少经过多少次操作才能让农夫追上奶牛。 --- #### 解决方案概述 此问可以建模为图上的 BFS 搜索问。为了防止重复访问某些节点并优化性能,通常会引入一个标记数组来记录已经访问过的状态。以下是解决方案的关键点: - 使用队列存储当前的状态 `(position, steps)`,其中 `position` 表示当前位置,而 `steps` 则是从起始点出发所花费的操作次数。 - 对于每一个可能的动作(即走一步或瞬间传送),将其加入队列以便后续处理[^1]。 - 如果某个动作超出了合理范围或者已经被访问过,则跳过它以减少不必要的计算开销[^2]。 下面提供了一个完整的C++程序实现这一逻辑: ```cpp #include <bits/stdc++.h> using namespace std; const int MAX_POS = 1e5; // 定义最大可达到的位置 int visited[MAX_POS + 1]; void bfs(int start, int end){ queue<pair<int,int>> q; memset(visited,-1,sizeof(visited)); q.push({start,0}); visited[start]=0; while(!q.empty()){ pair<int,int> current=q.front();q.pop(); if(current.first==end){cout<<current.second<<endl;return;} vector<int> next_positions={current.first*2,current.first+1,current.first-1}; for(auto &next_pos : next_positions){ if(next_pos>=0 && next_pos<=MAX_POS && visited[next_pos]==-1){ visited[next_pos]=current.second+1; q.push({next_pos,visited[next_pos]}); } } } } int main(){ ios::sync_with_stdio(false); cin.tie(NULL); int N,K; cin >> N >> K; bfs(N,K); } ``` 上述代码实现了基于BFS算法求解最小步数的功能,并考虑到了边界条件以及效率优化措施[^3]。 --- #### 关键技术细节说明 - **初始化**: 将所有位置设置成未被访问(-1),仅当某位置第一次被发现时才更新其对应的最少步骤数。 - **终止条件**: 当前探索的位置正好等于目标位置时立即停止搜索并输出结果。 - **剪枝策略**: 只有那些尚未访问且处于合法区间内的新位置才会被列入待考察列表之中[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值