P2220 [HAOI2012] 容易题 题解
toolong114514 · · 题解
P2220 [HAOI2012] 容易题 题解
题目大意
传送门。
解题思路
第一档部分分
对于
直接
void dfs(int pos,long long tmp){
//cout<<pos<<endl;
if(pos==m){
ans+=tmp;
ans%=mod;
return;
}
for(int i=1;i<=n;i++){
bool flag=false;
for(int j=1;j<=k;j++){
if(lim[j].p==pos+1&&lim[j].v==i){
flag=true;
break;
}
}
if(!flag) dfs(pos+1,(tmp*i)%mod);
}
}
特殊情况(第二档部分分)
对于另外
考虑推导没有限制的特殊情况(假定
记
显然,当
那么,
对于每一个长度为
得到递推式:
通项,得
此时,我们得到了
时间复杂度为
相信大家都会快速幂,就不放代码了吧。
第三档部分分
对于
在
时间复杂度为
核心代码:
f[0]=1;
for(int i=1;i<=m;i++){
f[i]=n*(n+1)/2*f[i-1];
memset(vst,false,sizeof(vst));
for(int j=1;j<=k;j++){
if(lim[j].p==i&&!vst[lim[j].v]){
f[i]-=lim[j].v*f[i-1];
vst[lim[j].v]=true;
}
}
}
cout<<f[m];
正解
我们发现,第三档部分分做法的复杂度瓶颈在
递推的时候,有很多没限制的地方可以直接计算,跳过去。
所以,只对存在限制的地方特别计算,剩下的直接用快速幂求即可。
时间复杂度为
参考代码
#include<algorithm>
#include<iostream>
using namespace std;
#define int long long
const int N=1e6+10;
const int mod=1e9+7;
struct ccf{
int p,v;
friend bool operator==(ccf a,ccf b){
return a.p==b.p&&a.v==b.v;
}
}lim[N];
bool cmp(ccf pre,ccf nxt){
if(pre.p!=nxt.p) return pre.p<nxt.p;
else return pre.v<nxt.v;
}
int qpow(int x,int mi){
int ans=1;
while(mi){
if(mi&1){
ans*=x;
ans%=mod;
}
x*=x;
x%=mod;
mi>>=1;
}
return ans%mod;
}
int fft=1;
int n,m,k;
signed main(){
ios::sync_with_stdio(false);
cin>>n>>m>>k;
if(k==0){
cout<<qpow(((n+1)*n/2)%mod,m);
return 0;
}
for(int i=1;i<=k;i++){
cin>>lim[i].p>>lim[i].v;
}
lim[k+1]={m,0};
sort(lim+1,lim+k+2,cmp);
int k1=unique(lim+1,lim+k+2)-lim;
int tmp=0,last=0;
for(int i=1;i<=k1;i++){
tmp+=lim[i].v;
if(lim[i].p!=lim[i+1].p){
fft*=qpow((n*(n+1)/2)%mod,lim[i].p-last-1);
fft%=mod;
fft*=((n*(n+1)/2)%mod-tmp%mod+mod)%mod;
fft%=mod;
last=lim[i].p;
tmp=0;
}
}
cout<<fft%mod;
return 0;
}
赛时写得比较丑陋。
注意事项
写代码时要特别注意取模的细节,不然你的正解会被卡在 70pts~90pts 左右!
Written by toolong114514 on 2024/3/16.
没见过题目名字这么嚣张的。