题意:对于一个数组,长度为n,当gcd(a[i],i)==1时可将此数删去,后面的数往前移。某个数组[2,3]的删去数组是[1,1]和[2,1],有两个,所以这种数组被定义为模糊数组。求长度为1-n,数字范围为1-m模糊数组的个数
思路:纯纯数学题
可以发现规律,只要存在一个数gcd=1那么这个数组就是模糊数组
一开始想用dp做 比如dp[i]表示数组长度为i时模糊数组的个数 然后转移方程写成了删除一个数后 后面的数不会前移的转移方程 所以最后结果比该题少
所以就要进一步拓宽规律
只要存在某个数a[i] gcd(1~i,a[i])都大于1,说明这个数一定只能在下标为1时删去。只要每一位都满足这个条件,那么这个数组就不是模糊数组
(判断这个条件时,只需要把前1-i的这些下标的质因子相乘得到yinzi,那么m/yinzi就代表满足该1-m中满足该条件数的个数,因为对于其它的数都能写成a*yinzi+b (b<yinzi) ,b无法被yinzi整除,说明b不能被yinzi中的某个质因子整除,也就是gcd=1,能在某一位置删除)
于是可以用逆向思维 先求出长度1-n数组的数量,再求出长度为i时不是模糊数组的数量。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=3e5+5;
const ll mod=998244353;
ll a[N];
ll gcd(ll x,ll y)
{
return y==0?x:gcd(y,x%y);
}
void solve()
{
int n;
ll m,cur=1,ans=0;
cin>>n>>m;
for (int i=1;i<=n;i++)
{
cur=(m%mod*cur)%mod;
ans=(ans+cur)%mod;//忘记题目是每个长度都要选
}
ll yinzi=1,bad=1;
for (int i=1;i<=n;i++)
{
if (gcd(yinzi,i)==1)
yinzi=yinzi*i;//要判断m与yinzi的大小 所有不能取模
if (m/yinzi==0)
break;
bad=((m/yinzi)%mod*bad)%mod;
ans=(ans-bad+mod)%mod;
}
cout<<ans;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t=1;
while (t--)
{
solve();
}
return 0;
}