zoukankan      html  css  js  c++  java
  • Jzoj5884. 【NOIP2018模拟A组9.25】蒲公英的约定

    Description

    wy 和 wjk 是好朋友。
    今天他们在一起聊天,突然聊到了以前一起唱过的《蒲公英的约定》。
    “说到蒲公英,我给你讲一个故事吧。”
    “嗯?”
    “从前有两朵蒲公英,他们约定一起长大,在 N 天内每一天都长出同样多的种子,可是, 他们不想让其他植物知道他们到底要长出多少种子,于是他们中的哥哥想出了一个办法,最 开始,他会告诉弟弟一个数 P,然后在接下来的若干天里每一天哥哥会告诉弟弟两个数:a,c, 然后弟弟在这一天会干如下几件事情:
    Step 1:首先把 c 和 lastans 按位异或得到 b,最开始 lastans 是 0
    Step 2:如果这天的 b 等于 0,则说明他们已经长出了所有要长出的种子,哥哥与弟弟的交 流结束(输入文件也到此结束)
    Step 3:如果这天的 b 不等于 0,弟弟会求出一个最小的非负整数 x 使得axb(modp)a^xequiv b( mod p) ,[题目保证可以找到这样的 x]
    Step 4:lastans 赋值为 x
    现在给你哥哥给弟弟的所有数字,你能求出每天弟弟要长出的种子的数量(即每天的 x)吗” “唔。。。”

    Input

    第一行一个整数 P 接下来若干行(不妨认为有 N+1 行),每行两个整数 a,c,含义如题目描述所示。

    Output

    一共 N 行,每行一个整数,第 i 行代表第 i 天弟弟要长出的种子的数量(即第 i 天的 x 的值) [第 N+1 天弟弟会在第二步停止,所以不用求出这一天的 x 输出,只作为输入文件结束的标 志]

    Sample Input

    17
    2 8
    8 11
    5 5
    4 12

    Sample Output

    3
    1
    12

    样例解释

    [以下 N 行,每行两个整数,第一个整数代表第 i 天的 a,第二个整数代表第 i 天的 b]
    2 8
    8 8
    5 4
    4 0

    Data Constraint

    对于 30%的数据 1 ≤ N ≤ 1000 1 ≤ P ≤ 1000
    对于 60%的数据 1 ≤ N ≤ 10000 1 ≤ P ≤ 60000
    另有 10%的数据 每一天的 a 都相等
    对于 100%的数据 1 ≤ N ≤ 100000 1 ≤ P ≤ 100000 且 P 是素数 a,b ≤ P-1

    题解

    这是一道吼题。
    %40
    直接暴力寻找x即可。
    %60~%100
    可以用GSBS(大步小步)
    大步小步算法是干嘛用的呢?
    也就是解决下面这个式子的:
    axb(modp)a^xequiv b( mod p)
    其中p为素数。
    然后a、b、p给定要求最小的正整数x为多少。
    ——一个显然的东西:x<px<p
    那么x就是在0~p这个范围内的一个整数啦。
    直接枚举是O(p)O(p)的,时间复杂度显然不准许。
    那么可以考虑优化——
    (以下就是GSBS的基本步骤)
    首先,我们设一个变量tru=ptru=lceil{sqrt{p}} ceil
    然后我们再分别设两个变量x,y
    i:1 trui:1~tru
    j:0 truj:0~tru
    那么x就可以表示为:
    x=itrujx=i*tru-j
    那么原式:
    axb(modp)a^xequiv b( mod p)
    变成
    aitrumodp=bajmodpa^{i*tru} mod p=b*a^j mod p
    那么就把bajb*a^j丢进hash里,
    再依次枚举i找答案即可。
    时间复杂度O(p)O(sqrt{p})
    似乎可以过。
    然而我比赛时打wei了,得分与暴力分一样。/_>
    100%
    震惊,原来题目这么水。
    我们发现,题目保证最后的b是0。
    也就是说可以考虑从后面的b给倒退回来。
    嘿嘿嘿~~
    所以就可以套上一个快速幂过掉。
    O(nlogp)O(n log p)

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    
    #define F(i, a, b) for (int i = a; i <= b; i ++)
    #define G(i, a, b) for (int i = a; i >= b; i --)
    #define max(a, b) ((a) > (b) ? (a) : (b))
    #define min(a, b) ((a) < (b) ? (a) : (b))
    #define mem(a, b) memset(a, b, sizeof a)
    #define mec(a, b) memcpy(a, b, sizeof a)
    #define mx(a, b) ((a) = max(a, b))
    #define mn(a, b) ((a) = min(a, b))
    
    #define N 400
    
    using namespace std;
    
    int P, a, b, lastans;
    struct node {
    	int x, y;
    	bool operator < (node s) const { return x < s.x || x == s.x && y < s.y; }
    } A[N];
    
    #define get getchar()
    inline void Re(int &x) {
    	char c = get; x = 0; int t = 1;
    	for (; !isdigit(c); c = get) t = (c == '-' ? - 1 : t);
    	for (; isdigit(c); x = (x << 3) + (x << 1) + c - '0', c = get); x *= t;
    }	
    inline void Wr(int x) {
    	if (x < 0) { putchar('-'); x = - x; }
    	if (x > 9) Wr(x / 10); putchar(x % 10 + '0');
    }
    
    int ksm(int x, int y) {
    	int ans = 1;
    	for (; y ; y >>= 1, x = (1LL * x * x) % P)
    		if (y & 1) ans = (1LL * ans * x) % P;
    	return ans;
    }
    
    int main() {
    	freopen("dandelion.in", "r", stdin);
    	freopen("dandelion.out", "w", stdout);
    
    	Re(P); int p = int(sqrt(P)) + 1;	
    	while (1) {
    		Re(a), Re(b), b ^= lastans, b %= P;
    		if (!b) return 0; A[0].x = 1, A[0].y = 0;
    		F(i, 1, p) A[i] = {(1LL * A[i - 1].x * a) % P, i};
    		sort(A + 0, A + p); int k = P / p;
    		F(i, 0, k) {
    			int v = (1LL * ksm(a, ((- i * p) % (P - 1) + (P - 1)) % (P - 1)) * b) % P;
    			int l = 0, r = p, ans = 0;
    			while (l <= r) {
    				int m = l + r >> 1;
    				if (A[m].x == v) ans = m;
    				if (A[m].x >= v) r = m - 1; else l = m + 1;
    			}
    			if (A[ans].x == v)
    				{ lastans = i * p + A[ans].y; break; }
    		}
    		Wr(lastans); puts("");
    	}
    }
    

    BSGS的算法

    uses math;
    var
            i,j,k,l,n,m,now:longint;
            p,a,b,c,tru,an,lastans,kk:int64;
            hash,id,x,y,answer:array[0..100000] of longint;
    
    function qsm(a,b,mo:int64):int64;
    var
            t,y:int64;
    begin
            t:=1;
            y:=a;
            while b<>0 do
            begin
                    if(b and 1)=1 then
                            t:=(t*y) mod mo;
                    y:=(y*y) mod mo;
                    b:=b shr 1;
            end;
            exit(t);
    end;
    
    begin
            assign(input,'dandelion.in');reset(input);
            assign(output,'dandelion.out');rewrite(output);
            readln(p);
            while not eof do
            begin
                    inc(n);
                    readln(x[n],y[n]);
            end;
            for i:=n downto 1 do
            begin
                    if i=n then
                    begin
                            answer[n]:=y[n];
                    end
                    else
                    begin
                            answer[i]:=(y[i] xor qsm(x[i],answer[i+1],p)) mod p;
                    end;
            end;
            for i:=2 to n do
            begin
                    writeln(answer[i]);
            end;
    end.
    
    我活在这夜里。无论周围多么黑暗,我都要努力发光!我相信着,终有一天,我会在这深邃的夜里,造就一道最美的彩虹。
  • 相关阅读:
    ZooKeeper实践:(1)集群管理
    删除重复数据只保留一条
    查询sqlserver 大小写
    字段按位数自动加空格
    批量更新数据遍历数据
    测试端口号是否开通
    收缩数据库
    插入ID=-1 的数据
    查询重复语句,多表查询
    oracle数据查询时间
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11148392.html
Copyright © 2011-2022 走看看