模拟60 考试总结

考试经过

发现都不太可做猜测场分不会高,果断投身暴力
T1大力测试点分治30,T2好不容易把基础dp写了30,T3T4写暴力,结果假了
30+30+0+0=60,把暴力基本写了,但是T3基础dp不难,T4也不应该挂
现在再想如果发现后两题不好得分,策略应该是肝T2正解,毕竟已经看出来矩阵了

T1.整除

这个式子直接不太好做,先给结论 :
把每个指数范围内求出对应的答案,然后再乘起来
这种题考场做法其实应该大力拆样例找规律,看到合数要对每个质数有点想法
证明靠WYZG,感觉思路比较清晰
CRT拿来不一定要解方程,也可以来证明某种做法是对的
然后直接暴力枚举,快速幂判断有80,满分可以线性筛,但战神有个贼神的原根做法 :
给出\(p\mid x^m-x\),要求\(1\)\(p\)\(x\)的解个数
设模\(p\)意义下\(x\)的原根为\(g\),设\(x\equiv g^i\pmod{p}\),则有

\[g^{mi}-g^i\equiv 0\pmod{p} \]

由于\(mi\)比较大,这里利用欧拉定理就有\(mi\equiv i\pmod{p-1}\)
于是移项就有\(p-1\mid i\times (m-1)\)
由于\(i\)的数量唯一对应\(x\)的数量,所以就是求满足条件\(i\)的个数
答案即为\(i/(i/\gcd(p-1,m-1))\),就是\(\gcd(p-1,m-1)\)
因为没有考虑\(x=p\)的情况,所以最后答案要加上1
所以数据可以直接开到\(10^{18}\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
int a[55];
inline int gcd(int x,int y)
{
	if(!y)return x;
	return gcd(y,x%y);
}
signed main()
{
	freopen("division.in","r",stdin);
	freopen("division.out","w",stdout);
	int id;cin>>id;
	int t;scanf("%lld",&t);
	while(t--)
	{
		int c,m;scanf("%lld%lld",&c,&m);
		for(int i=1;i<=c;i++)scanf("%lld",&a[i]);
		int n=1,ans=1;
		for(int i=1;i<=c;i++)n=n*a[i]%mod;
		for(int i=1;i<=c;i++)
		{
			int an=0;
		   an=gcd(a[i]-1,m-1)+1;
		   ans=ans*an%mod;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

T2.糖果

\(f_{i,j}\)表示当前考虑到第\(i\)种糖,总共选了\(j\)个方案数
那么转移就是\(f_{i,j}=\sum_{k=0}^{\min(a_i,j)}f_{i-1,j-k}\times \dbinom{j}{j-k}\)
后面的组合数就是要在\(j_k+1\)个位置填\(k\)个数,相当于划分,由于允许空,等价于\(j+1\)分成不空\(k\)
考虑优化,注意到这里问题主要在于\(a_i\)的值,发现大于\(m\)的都是\(m\),所以可以对每种取值分开计算
然后试图改一改方程,把第一维搞掉,问题就是怎么求\(a_i\)
同余递推显然会循环,暴力枚举\(10^7\),然后开桶记录出现次数
显然后面可以矩阵优化,分别配出来矩阵做就行了
复杂度上界应该\(m^4\),不过跑不满,题解复杂度更优,直接用了倍增方程转移

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e7+30;
const int mod=998244353;
int n,m,a[N],p[N];
int sum[105],s;
int jc[105],inv[105],jcny[105];
inline void pre()
{	
	jc[0]=jc[1]=inv[1]=jcny[0]=jcny[1]=1;
	for(int i=2;i<=102;i++)
	{
		jc[i]=jc[i-1]*i%mod;
		inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		jcny[i]=jcny[i-1]*inv[i]%mod;
	}
}
inline int C(int x,int y)
{
	if(x<y)return 0;
	if(!y)return 1;
	return jc[x]*jcny[y]%mod*jcny[x-y]%mod;	
}
int g[105],f[105];
int t[105][105],pp[105][105];
inline void mul()
{
	memset(pp,0,sizeof(pp));
	for(int i=0;i<=m;i++)
	 for(int k=0;k<=m;k++)
	  for(int j=0;j<=m;j++)
	   pp[i][j]=(pp[i][j]+t[i][k]*t[k][j]%mod)%mod;
	memcpy(t,pp,sizeof(pp));
}
inline void gan()
{
	memset(g,0,sizeof(g));
	for(int i=0;i<=m;i++)
	 for(int j=0;j<=m;j++)
	  g[i]=(g[i]+f[j]*t[j][i]%mod)%mod;
	memcpy(f,g,sizeof(f));
}
inline void getp(int n)
{
	memset(t,0,sizeof(t));
	for(int i=0;i<=m;i++)
	 for(int j=0;j<=min(n,i);j++)
	  t[i-j][i]=C(i,i-j);
}
inline void ksm(int x)
{
	for(;x;x>>=1)
	{
		if(x&1)gan();
		mul();
	}
}
signed main()
{
	freopen("sugar.in","r",stdin);
	freopen("sugar.out","w",stdout);
	cin>>n>>m;int A,B,P;
	cin>>a[1]>>A>>B>>P;
	p[a[1]]=1;pre();
	int from=1,to=1;
	for(int i=2;i<=min(n,(int)2e7);i++)
	{
		a[i]=(a[i-1]*A+B)%P+1;
		if(p[a[i]]){from=p[a[i]];break;}	
		p[a[i]]=i;to=i;
	}
	for(int i=1;i<from;i++)
	{	
		if(a[i]<m)sum[a[i]]++;
		else s++;
	}
	int num=(n-(from-1))/(to-from+1);
	for(int i=from;i<=to;i++)
	{
		if(a[i]<m)sum[a[i]]+=num;
		else s+=num;
	}
	for(int i=from;i+(to-from+1)*num<=n;i++)
	{
		if(a[i]<m)sum[a[i]]++;
		else s++;
	}
	f[0]=1;
	for(int i=0;i<m;i++)
	{
		if(!sum[i])continue;
		getp(i);ksm(sum[i]);
	}
	getp(m);ksm(s);
	cout<<f[m]<<endl;
	return 0;
}

T3.打字机

dp好题,见

T4.堆

没人改出来,咕

考试总结

1.正确选择策略,拿尽量高的分
2.不要使得分停止,下次不要出现估分0的东西

posted @ 2021-09-24 07:30  D'A'T  阅读(28)  评论(1)    收藏  举报