HDU多校day1-1007Pass!

本文介绍了如何利用动态规划和数学方法解决一类递推序列模运算的问题。通过建立递推关系,求解特征方程,找到通项公式,并使用BSGS算法求解模P的指数方程。文章给出了具体的代码实现,展示了如何在高精度环境下快速计算符合条件的最小时间值。

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

Pass!

题意:

nnn个人,最开始,第一个人拿球。每秒每个人可以把球传给任意一个其他人。ttt秒过后,球回到第一个人的传球序列方案数取模998244353998244353998244353后为xxx。给nnnxxx求满足条件最小的ttt

思路:

由于最后一秒要回到第一个人,那么时间为ttt的时候,球在111手上。由于不能传球给自己,那么时间为t−1t-1t1的时候,球肯定在x(x≠1)x(x\neq 1)x(x=1)手上。
ttt秒的时候,方案数为f(t)f(t)f(t)
我们可以讨论时间为t−2t-2t2的时候,球有可能在111手上,也有可能在其他人手上。

  • 如果球在111手上,那么就相当于时间在t−2t-2t2的时候就传回111的方案数f(t−2)f(t-2)f(t2),再乘上下一步可能传给除111以外的其他人人数n−1n-1n1
  • 如果球在x(x≠1)x(x\neq 1)x(x=1)手上,那么就相当于在t−1t-1t1的时候的方案的倒数第二步和最后一步之间加上一步,这一步可能传给除111xxx之外的其余n−2n-2n2个人。

所以我们可以得到通向公式:f(t)=(n−2)f(t−1)+(n−1)f(t−2)f(t)=(n-2)f(t-1)+(n-1)f(t-2)f(t)=(n2)f(t1)+(n1)f(t2)
通过特征方程,我们设f(t)−xf(t−1)=s(f(t−1)−xf(t−2))f(t)-xf(t-1)=s(f(t-1)-xf(t-2))f(t)xf(t1)=s(f(t1)xf(t2))
可得:{s+x=n−2−sx=n−1\left\{\begin{aligned}s+x=n-2\\-sx=n-1\end{aligned}\right.{s+x=n2sx=n1
消元sss得:x2−(n−2)x−(n−1)=0x^2-(n-2)x-(n-1)=0x2(n2)x(n1)=0
解方程:
∵Δ=b2−4ac=n2\because\Delta=b^2-4ac=n^2Δ=b24ac=n2
∴x1=n−1,x2=−1\therefore x_1=n-1,x_2=-1x1=n1,x2=1
所以可以得到通项公式方程f(t)=A(n−1)t+B(−1)tf(t)=A(n-1)^t+B(-1)^tf(t)=A(n1)t+B(1)t
{f(0)=A+B=1f(1)=A(n−1)+B(−1)=0\left\{\begin{aligned}f(0)&=A+B=1\\f(1)&=A(n-1)+B(-1)=0\end{aligned}\right.{f(0)f(1)=A+B=1=A(n1)+B(1)=0
解,得:{A=1nB=n−1n\left\{\begin{aligned}A&=\cfrac{1}{n}\\B&=\cfrac{n-1}{n}\end{aligned}\right.AB=n1=nn1
所以可以得到通项公式f(t)=(n−1)t+(n−1)⋅(−1)tnf(t)=\cfrac{(n-1)^t+(n-1)\cdot(-1)^t}{n}f(t)=n(n1)t+(n1)(1)t
就将问题化成了求f(t)≡xmod  Pf(t)\equiv x \mod Pf(t)xmodP的解。
f(t)f(t)f(t)分奇偶讨论,可以得到:
{[(n−1)2]x≡nx−(n−1)t=2x[(n−1)2]x≡nxn−1+1t=2x+1\begin{cases}[(n-1)^2]^x\equiv nx-(n-1) &t=2x \\ [(n-1)^2]^x\equiv \cfrac{nx}{n-1}+1&t=2x+1\end{cases}[(n1)2]xnx(n1)[(n1)2]xn1nx+1t=2xt=2x+1
可以采用解ax≡bmod  Pa^x\equiv b\mod PaxbmodP的BSGS算法求解。
因为有点卡常,所以用unordered_map,并且移一下相,减少一次求解次数。

代码:

#pragma GCC optimize(2)
#include<iostream>
#include<math.h>
#include<unordered_map>
#define int long long
const int N=1e6+10;
const int mod=998244353;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
const double pi=acos(-1);
const double INF=1e18;
using namespace std;

int qpow(int a,int b)
{
	int ans=1;
	while(b)
	{
		if(b&1)
			ans=ans*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return ans;
}
int M=sqrt(mod)+1;
unordered_map<int,int> m;
signed main()
{
	int T;
	scanf("%lld",&T);
	while(T--)
	{
		int n,x;
		scanf("%lld%lld",&n,&x);
		int b1=(n*x-(n-1)+mod)%mod,b2=(n*x%mod*qpow(n-1,mod-2)%mod+1)%mod;
		int a=(n-1)*(n-1)%mod;
		m.clear();
		if(b1==1)
		{
			puts("0");
			continue;
		}
		if(b2==1)
		{
			puts("1");
			continue;
		}
		int p=1,f=0,i;
		for(i=0;i<M;i++)
		{
			m[p]=i;
			p=p*a%mod;	
		}
		b1=qpow(b1,mod-2);
		b2=qpow(b2,mod-2); 
		int tt=qpow(a,M),t=tt; 
		for(i=1;i<=M+1;i++)
		{
			if(m[t*b1%mod])
			{
				printf("%lld\n",2*(i*M-m[t*b1%mod]));
				f=1;
				break; 
			}
			if(m[t*b2%mod])
			{
				printf("%lld\n",2*(i*M-m[t*b2%mod])+1);
				f=1;
				break;
			}
			t=t*tt%mod; 
		}
		if(f==0)
			puts("-1");
				
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值