HDU-6004-Periodical Cicadas

来源:互联网 发布:运营淘宝店要学什么 编辑:程序博客网 时间:2024/06/06 01:50

ACM模版

描述

描述

题解

nm 的区域中,有 nm 种知了,给出每种知了第一次出现的年数 s 和周期性 z,然后询问 (x1,y1)(x2,y2) 为对角线顶点的矩形区域中,所有种类知了同时出现的年份。

这里要求矩形区域中所有知了第一次同时出现的年数,我们可以先从两只知了考虑,设甲第一次出现、甲出现周期、甲出现的次数、甲出现的年数、乙第一次出现、乙出现周期、乙出现的次数、乙出现的年数为 s1z1c1d1s2z2c2d2,那么我们很容易得到:

d1=s1+c1z1
d2=s2+c2z2

因为想要两只同时出现,所以使 d1=d2 联立得:

s1+c1z1=s2+c2z2
c1z1c2z2=s2s1

所以利用扩展欧几里得我们可以得到 c1 的最小正整数解,代入可得 d 值。这样得到了第一次两只知了同时出现的年数,那么以后两只知了同时出现的年数也是周期性的,周期为 lcm(z1,z2)

考虑完两只知了的合并后,就可以考虑更多的合并了,其实我们完全可以将已经合并的两只看成一只,然后再与其他的进行合并,如此这般我们便能很容易获得到任意只知了同时出现的时间。

由于题目 0<n,m200,但是 0<150000,所以我们需要先预处理出来一些信息这样才能更好的优化访问。我们不妨用 DPdp[i][j][k] 表示第 i 行从 jk 的知了同时出现的时间。那么我们预处理完这个后,当我们访问时只需要对纵向进行合并即可。

现在来分析复杂度,首先预处理的复杂度是 O(n3),在允许范围内,询问时的复杂度是 O(qn) 也是可以接受的,但是我们的空间复杂度有些高,我们需要对空间进行压缩。常见的 dp[][][] 的压缩手段是滚动数组,压掉第一维,可是我们这里需要保留第一维的信息,所以这种手段是不行的,那么我们可以选择的还有压缩第二和第三维。具体怎么压缩呢?我们不妨来只考虑后两维这个空间,想象成矩阵,jk 一定满足的关系是 j<k,那么在这个矩阵中,我们会用到的空间只有上三角,下三角空间完全是搁置的,我们不如对 jk 进行 hash,这样就可以实现压缩掉这搁置的一半还多的空间。如此这般,便很容易将三维降低到二维,不过空间只是压缩了一半。

除此之外,还有一个比较明显的问题便是 longlong 会爆,在计算的时候产生的中间变量会爆掉 longlong,所以那部分我们需要用更大的数据类型来保存,恰好有一个叫做 __int128 的玩意儿,可以好好用用。

代码

#include <iostream>#include <algorithm>using namespace std;typedef long long ll;typedef __int128 lll;const int MAXN = 202;const int MAXM = MAXN * MAXN / 2 + MAXN;struct node{    ll a, b;} dp[MAXN][MAXM];int n, m, q;inline int _hash(int x, int y){    return (2 * m - x + 1) * x / 2 + y - x + 1;}ll exgcd(ll a, ll b, ll &x, ll &y){    if (b == 0)    {        x = 1;        y = 0;        return a;    }    ll ans = exgcd(b, a % b, x, y);    ll t = x;    x = y;    y = t - a / b * y;    return ans;}node merge(node x, node y){    if (x.a == -1 || y.a == -1)    {        return {-1, -1};    }    ll _x, _y;    ll g = exgcd(x.b, y.b, _x, _y);    if ((y.a - x.a) % g)    {        return {-1, -1};    }    ll t = (y.a - x.a) / g;    lll p = x.a + (lll)x.b * _x * t;    lll q = x.b / g * y.b;    p = (p % q + q) % q;    return {(ll)p, (ll)q};}void init(){    for (int i = 0; i < n; i++)    {        for (int j = 0; j < m; j++)        {            for (int k = j + 1; k < m; k++)            {                dp[i][_hash(j, k)] = merge(dp[i][_hash(k, k)], dp[i][_hash(j, k - 1)]);            }        }    }}int main(int argc, const char * argv[]){    int T;    cin >> T;    for (int ce = 1; ce <= T; ce++)    {        printf("Case #%d:\n", ce);        scanf("%d%d", &n, &m);        for (int i = 0; i < n; i++)        {            for (int j = 0; j < m; j++)            {                scanf("%lld", &dp[i][_hash(j, j)].a);            }        }        for (int i = 0; i < n; i++)        {            for (int j = 0; j < m; j++)            {                scanf("%lld", &dp[i][_hash(j, j)].b);            }        }        init();        scanf("%d", &q);        int x1, y1, x2, y2;        while (q--)        {            scanf("%d%d%d%d", &x1, &y1, &x2, &y2);            x1--; y1--; x2--; y2--;            node ans = dp[x1][_hash(y1, y2)];            for (int i = x1 + 1; i <= x2; i++)            {                if (ans.a == -1)                {                    break;                }                ans = merge(ans, dp[i][_hash(y1, y2)]);            }            printf("%lld\n", ans.a);        }    }    return 0;}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 a37手机网站被劫持怎么办 耳朵被震的耳鸣怎么办 液晶电视怎么办断屏坏还是逻辑板 门保险拧坏了怎么办 锁的保险坏了怎么办 鞋子里面长霉了怎么办 塑料瓶盖滑丝了怎么办? 塑料杯盖滑丝了怎么办 洗衣机上的订子很难扭出来怎么办 滚筒洗衣机坏了打不开门怎么办 海尔滚筒洗衣机打不开门怎么办 格兰仕滚筒洗衣机门打不开怎么办? lg洗衣机洗完衣服门打不开怎么办 lg洗衣机不能冼衣服怎么办 vivo账户密码忘记了怎么办 oppo账户密码忘记了怎么办 74160从1开始计数怎么办 微信录音声音小怎么办 word文档已停止工作怎么办 怀孕30天不想要怎么办 一楼墙体起碱怎么办 农村平房顶四墙面渗水怎么办 被蝎子精蛰了怎么办 小娃头摔包要怎么办抹个什么 老人死了银行钱存死期怎么办 飙酷车神2一进画面就闪退怎么办 电脑开机键盘鼠标没反应怎么办 玩gta4自由城卡怎么办 gta5游戏服务当前不可用怎么办 健身后胳膊变粗怎么办 健身后手臂变粗怎么办 家猫见到我就跑怎么办 走路多了小腿酸痛怎么办 脚有脚气很痒怎么办 地板精油喷多了怎么办 史莱姆泥变硬了怎么办 dnf剑帝命中率低怎么办 无意中讲话伤害了人怎么办 高中上不下去了怎么办 高三坚持不下去怎么办 word点了不保存怎么办