P10138 [USACO24JAN] Cowmpetency G
Genius_Star · · 题解
思路:
感觉不错,中等蓝吧……
考虑对第
那么我们需要对于一个限制
因为该限制需要满足:
则区间
经过这样的判断,如果一个点既一定又不可能,那么就无解。
然后考虑动态规划算法,定义
很容易想到用前缀和优化,定义:
状态转移方程优化为:
时间复杂度为
但是因为
定义第
其中
这个也可以进行前缀和优化:
这样加上快速幂的计算,时间复杂度为
完整代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const ll Q=505,N=10100,mod=1e9+7;
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
inline void write(ll x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
struct St{
ll l,r;
bool operator<(const St&rhs)const{
if(r==rhs.r)
return l<rhs.l;
return r<rhs.r;
}
}h[N];
ll n,q,c,cnt=0,l=1;
ll A[Q],op[Q];
ll dp[Q][N],s[Q][N];
ll qpow(ll a,ll b){
ll ans=1;
while(b){
if(b&1ll)
ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1ll;
}
return ans;
}
int main(){
// freopen("A.in","r",stdin);
// freopen("A.out","w",stdout);
n=read(),q=read(),c=read();
for(int x,y,i=1;i<=q;i++){
x=read(),y=read();
h[i]={x+1,y};
}
sort(h+1,h+q+1);
for (int i=1;i<=q;i++){
if(h[i].r==h[i-1].r)
continue;
if(l>h[i].l){
puts("0");
exit(0);
}
if(l<h[i].l){
cnt++;
A[cnt]=h[i].l-l;
op[cnt]=0;
}
if(h[i].l<h[i].r){
cnt++;
A[cnt]=h[i].r-h[i].l;
op[cnt]=-1;
}
cnt++;
A[cnt]=1;
op[cnt]=1;
l=h[i].r+1;
}
if(h[q].r<n){
cnt++;
A[cnt]=n-h[q].r;
op[cnt]=0;
}
// for(int i=1;i<=cnt;i++){
// write(op[i]);
// putchar(' ');
// }
// putchar('\n');
dp[0][0]=1;
for(int i=0;i<=c;i++)
s[0][i]=1;
for(int i=1;i<=cnt;i++){
for(int j=1;j<=c;j++){
ll x=qpow(j,A[i]),y=qpow(j-1,A[i]);
if(op[i]==-1)
dp[i][j]=(dp[i-1][j]*x)%mod;
else if(!op[i])
dp[i][j]=(((x-y+mod)%mod*s[i-1][j-1])%mod+(dp[i-1][j]*x)%mod)%mod;
else
dp[i][j]=s[i-1][j-1];
s[i][j]=(s[i][j-1]+dp[i][j])%mod;
}
}
// for(int i=1;i<=cnt;i++){
// for(int j=1;j<=c;j++){
// write(s[i][j]);
// putchar(' ');
// }
// putchar('\n');
// }
write(s[cnt][c]);
return 0;
}