C. 三人成行
- 计数问题的核心是不重不漏。本题中,在同一个序列中合法的(x,y,z,u)可能在多个位置出现,为了避免重复,我们取最左边的位置作为代表,一旦符合题意就把它计入答案并终止后续的状态转移
- 纠结局部会把自己弄晕的!拒绝晕倒,能不能从整体考虑,不记录当前的匹配情况,直接判定当前序列是否已经满足条件?完全可以!而且,一步步匹配一点都不美
- 另一方面,你已经观察到使序列合法的子区间状态是有限的,进一步,这些合法状态完全可以通过压缩后缀和表示。而且,题目告诉你的条件是\(X+Y+Z \leq 17\),何必弱化为\(X,Y,Z \leq 15\)呢
#include <bits/stdc++.h>
using namespace std;
const int mod=1000000007;
long long f[45][1<<18],ans;
int n,X,Y,Z;
bool fx,fy,fz;
int i,l,s,t;
int power(int n,int p)
{
if(p==0)
{
return 1;
}
long long tmp=power(n,p/2);
if(p%2==1)
{
return tmp*tmp%mod*n%mod;
}
return tmp*tmp%mod;
}
void dfs(int n1)
{
if(n1==-1)
{
if(fx&&fy&&fz)
{
ans=(ans+f[i][s]*power(10,n-i-1)%mod)%mod;
}
else
{
(f[i+1][t]+=f[i][s])%=mod;
}
}
else
{
for(int i=0;i<2;i++)
{
if(n1+l<Z)
{
t=t+i*(1<<(n1+l));
}
if(i==1)
{
if(n1+l==X)
{
fx=true;
}
if(n1+l==Y)
{
fy=true;
}
if(n1+l==Z)
{
fz=true;
}
}
s<<=1;
s+=i;
dfs(n1-1);
s-=i;
s>>=1;
if(i==1)
{
if(n1+l==X)
{
fx=false;
}
if(n1+l==Y)
{
fy=false;
}
if(n1+l==Z)
{
fz=false;
}
}
if(n1+l<Z)
{
t=t-i*(1<<(n1+l));
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>X>>Y>>Z;
Y=X+Y;
Z=Y+Z;
f[0][1]=1;
t=1;
for(i=0;i<n;i++)
{
for(l=1;l<=10;l++)
{
dfs(Z-1);
}
}
cout<<ans<<endl;
return 0;
}
D. Yt函数
- \(gcd(x,y)=gcd(x,n-x)=gcd(x,n)\)