JZOJ5884. 【NOIP2018模拟A组9.25】蒲公英的约定

两位好友回忆起《蒲公英的约定》,引出一个关于数学与编程的谜题。谜题中,两朵蒲公英约定在N天内每天长出同样数量的种子,但不希望其他植物知晓具体数量。哥哥发明了一个巧妙的方法,利用异或运算和快速幂算法,弟弟需求解每日种子数量。题目要求解决这一数学谜题,找出弟弟每天需要长出的种子数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

题解

很显然可以用BSGS,
这样是O(nn)O(n\sqrt n)O(nn)
其实还有更机智的做法,
显然,通过最后一行,
就可以知道上一次的答案,因为它异或c=0,
知道上一次的答案之后,就可以用快速幂求出上一次的b,
通过b跟再上一次的c就可以求出了再上一次的答案。
以此类推。

code

#include <queue>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <time.h>
#define ll long long
#define N 100003
#define P putchar
#define G getchar
using namespace std;
char ch;
void read(int &n)
{
	n=0;
	ch=G();
	while((ch<'0' || ch>'9') && ch!='-')ch=G();
	ll w=1;
	if(ch=='-')w=-1,ch=G();
	while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
	n*=w;
}

void write(ll x){if(x>9) write(x/10);P(x%10+'0');}

int p,n,a[N],b[N],c[N],ans[N];

int ksm(ll x,int y)
{
	ll s=1;
	for(;y;y>>=1,x=x*x%p)
		if(y&1)s=s*x%p;
	return s;
}

int main()
{
	freopen("dandelion.in","r",stdin);
	freopen("dandelion.out","w",stdout);
	
	for(read(p),n=1;scanf("%d",&a[n])!=EOF;n++)read(c[n]);
	
	n--;ans[n-1]=c[n];
	for(int i=n-1;i;i--)
	{
		b[i]=ksm(a[i],ans[i]);
		ans[i-1]=b[i]^c[i];
	}
	for(int i=1;i<n;i++)write(ans[i]),P('\n');
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值