模拟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}\),则有
由于\(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的东西

浙公网安备 33010602011771号