首页 > 其他分享 >P11211 随机数生成器 题解

P11211 随机数生成器 题解

时间:2024-10-20 22:59:04浏览次数:6  
标签:P11211 return int 题解 生成器 1ll mytz inline mod

前置知识:原根,exCRT

首先 \(t=1\) 是容易的,直接相邻的除一下即可。


否则考虑询问除连续的 \(5\) 个数,分别为 \(a_0,a_1,\cdots,a_4\)。

首先特判掉存在 \(a_i=0\) 的情况,此时直接枚举 \(s\) 即可。

我们先求出 \(p\) 的一个原根 \(g\),设离散对数 \(\log(x)=y\) 表示 \(g^y\equiv x\pmod p\)。

否则我们枚举 \(x\),并且 \(x\sim x+4\) 没有一个是 \(\bmod p=0\)。

此时我们有 \(5\) 个线性同余方程:\(\forall 0\le i<5,s\log (x+i)\equiv \log a_i\pmod {p-1}\)。

除掉 \(\gcd\),留下合法的方程,然后 exCRT 合并所有方程。

最终我们得到了 \(s\equiv A\pmod B\),其中 \(B\) 是 \(p-1\) 的因子。

然后我们枚举 \(s=Bk+A,k\in [0,(p-1)/B)\),然后判断 \((s,x)\) 是否合法即可。

复杂度是所有的 \((p-1)/B\) 之和乘一些 exgcd 的 \(\log\)。

写个程序算一下,这个和的上界大概是不超过 \(2p\) 的,即 \(4\times 10^6\),常数稍微写优秀一点就足以通过了。

#include<bits/stdc++.h>
#define LL long long
#define fr(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
#define ff fflush(stdout)
using namespace std;
const int N=2e6+5;
int id,mod,g,a[5],lg[N];bool v[N];
inline int ask(){puts("?");ff;int x;scanf("%d",&x);return x;}
inline int md(int x){return x>=mod?x-mod:x;}
inline int ksm(int x,int p){int s=1;for(;p;(p&1)&&(s=1ll*s*x%mod),x=1ll*x*x%mod,p>>=1);return s;}
#define mytz __builtin_ctz
inline int gcd(int a,int b)
{
	int az=mytz(a),bz=mytz(b),z=min(az,bz),diff;b>>=bz;
	while(a) a>>=az,diff=a-b,az=mytz(diff),b=min(a,b),a=abs(diff);return b<<z;
}
namespace GG
{
	int n;vector<int>g;
	inline int ksm(int x,int p){int s=1;for(;p;(p&1)&&(s=1ll*s*x%n),x=1ll*x*x%n,p>>=1);return s;}
	inline bool isy(int x){if(gcd(x,n)>1) return 0;for(int i:g) if(ksm(x,i)==1) return 0;return 1;}
	inline int gg(int x)
	{
		g.clear();int t=(n=x)-1,y=t;
		for(int i=2;i*i<=y;i++) if(y%i==0){while(y%i==0) y/=i;g.push_back(t/i);}(y^1)&&(g.push_back(t/y),1);
		for(int i=1;i<x;i++) if(isy(i)) return i;
	}
}//离散对数板子
inline bool chk(int x,int s){for(int i=0;i<5;i++) if(1ll*s*lg[md(x+i)]%(mod-1)!=a[i]) return 0;return 1;}
void exgcd(int a,int b,int &x,int &y)
{
	if(!b) return x=1,y=0,void();
	exgcd(b,a%b,x,y);int t=x;
	x=y;y=(t-(a/b)*y);
}
inline int inv(int x,int p){int a,b;exgcd(x,p,a,b);return (a%p+p)%p;}
inline void mg(int &X,int &L,int x,int y)
{
	if(!L) return L=x,X=y,void();int _x,_y,ll=L/gcd(L,x)*x;
	exgcd(L,x,_x,_y);_x=(LL)(y-X)/gcd(L,x)*_x%ll;_x=(_x+ll)%ll;
	X=((LL)L*_x+X)%ll;L=ll;
}//exgcd,excrt 板子
int main()
{
	scanf("%d%d",&id,&mod);
	if(id==1)
	{
		int A=ask(),B=ask();
		return printf("! %d\n",1ll*B*ksm(A,mod-2)%mod),0;
	}
	g=GG::gg(mod);
	for(int i=0,s=1;i<mod-1;i++,s=1ll*s*g%mod) lg[s]=i;//原根离散对数
	for(int i=0;i<5;i++) a[i]=ask();
	for(int i=0;i<5;i++) if(!a[i])
	{
		int x=md(mod-i);
		for(int s=0;s<mod-1;s++) if(chk(x,s))
			return printf("! %d\n",s),0;
	}
	for(int i=0;i<5;i++) a[i]=lg[a[i]];
	for(int x=1;x+4<mod;x++)//枚举 x
	{
		int X=0,L=0;bool o=1;
		for(int j=0;j<5;j++)
		{
			int t=md(j+x);
			if(t==1) continue;
			int A=lg[t],B=a[j],C=mod-1,g=gcd(A,C);
			if(B%g){o=0;break;}A/=g,B/=g,C/=g;//除掉 gcd
			mg(X,L,C,1ll*B*inv(A,C)%C);//excrt 合并同余方程
		}
		if(!o) continue;
		for(int j=X;j<mod-1;j+=L) if(chk(x,j))
			return printf("! %d\n",j),0;//枚举求解
	}
	printf("! 1\n");
	return 0;
}

标签:P11211,return,int,题解,生成器,1ll,mytz,inline,mod
From: https://www.cnblogs.com/HaHeHyt/p/18488070

相关文章

  • 可迭代对象、迭代器、生成器
    可迭代对象如果实现了__iter__方法,就认为对象是可迭代的.使用内置的iter函数可以获取迭代器的对象.检查对象x是否为迭代器,最好的方式是调用isinstance(x,abc.Iterator)序列都是可迭代的迭代器(Iterator):迭代器是一个对象,它实现了iter()和next()两个基本方法。ite......
  • 10.18Python基础迭代器生成器_函数式编程
    Python迭代器与生成器1.迭代器Iterator什么是迭代器迭代器是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器可以重复使用,而不会像列表那样在迭代时被修改。迭代器函数iter和next函数说明iter(iterable)从可迭代对象中返回一个迭代器,iterabl......
  • 牛客周赛Round64-B题题解
    牛客周赛Round64-B题题解题目描述:小红拿到了一个正整数,请你帮小红将其表示为幂(a^b)的形式。输入描述:一个正整数2<=x<=10^5输出描述:`第一行输出x。接下来每一行输出一个幂的表达式。请按指数从小到大的顺序输出。示例1输入16输出16=16^1=4^2=2^4解题思路:......
  • 【秋招笔试-支持在线评测】10.19京东秋招(已改编)-三语言题解
    ......
  • 【秋招笔试-支持在线评测】10.19小米秋招(已改编)-研发岗题解
    ......
  • [20241024] T3 题解
    细节挺多的。题意有一个长度为\(n\)的数组\(a\)和一个长度为\(m\)的队列\(q\),初始时\(q\)中的元素和为\(0\)。对\(x=1,2,\cdots,n\)进行如下操作:如果队首元素\(q_1<a_x\),则\(q\)弹出队首,将\(a_x\)插入队尾。在操作结束后,定义数组\(a\)的权值为\(q\)......
  • 2024 ICPC Asia Taiwan Online Programming Contest题解记录
    比赛链接:https://codeforces.com/gym/105383/problemA.AnimalFarm找个最大pig,然后所有比他小的其他种类生物一直加就好了#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constllmod=1e9+7;llksm(llx,lly){ llans=1; while(y) { if(y&1)......
  • P10233 [yLCPC2024] A. dx 分计算 题解
    题目大意:题目传送门共\(T\)组测试数据,每组数据给定一个字符串\(s\)和\(Q\)次询问,按照特定的赋值方式,每次询问\(l\)到\(r\)间按这样的赋值方式的总和是多少。赋值方式如下:P可得3分p可得2分G可得1分其余字符不得分题目分析:前置知识:前缀和。(没有学过的可以先......
  • 题解:AT_abc376_c [ABC376C] Prepare Another Box
    很好的一道二分答案题。听说CSP考前写tj可以让rp+=inf?注:下文中\(w\)指物品重量序列,\(x\)指箱子容量序列。先问个问题:为什么我上来就敢肯定这是个二分答案题?或者说,单调性在哪儿?非常简单:如果一个盒子的容量越大,能装下的东西就更多(废话)。那么如果\(v\)不够用,可以扩......
  • 【学校训练记录】10月个人训练赛4个人题解
    A:要使s,t相等只要互相删除对方没有的字母即可,即找到a-z字母拥有最少的#include<bits/stdc++.h>#defineendl"\n"#defineintlonglongusingnamespacestd;strings1,s2;inta1[30],a2[30];voidsolve(){ cin>>s1>>s2; for(inti=0;i<s1.size(......