http://codeforces.com/problemset/problem/1000/D
参考自:https://www.cnblogs.com/hua-dong/p/9238795.html
题意:给定序列,问有多少子序列(不一定连续),满足可以划分为若干个组,给个组的第一个等于区间长度-1;
思路:关键就在于区间的开头,由此我们从后往前考虑,dp[ i ] 表示以 i 开头,满足题意的数量,sum[ i ] 表示 i 及以后所有的可能情况。
对于 i ,可选的区间为 [ i , j ] , j 的范围是 i+a[ i ] ~ n,再利用选定的思想,这一段区间的可能情况就有 C ( a[ i ] -1 , j - i -1 ) ,接着,再乘上(1+sum[ j +1 ]),
这就是对乘法思想的利用,而这个 1 代表只选前面一个段的情况,通过不断的累加就得到 dp[ i ],再累加就得到 sum[ i ]。
#include<bits/stdc++.h> #define ll long long using namespace std; const int Mod=998244353; const int maxn=1010; int a[maxn],dp[maxn],sum[maxn]; int c[maxn][maxn],ans; int main() { int N,i,j; scanf("%d",&N); for(i=0;i<=N;i++) c[i][0]=1,c[i][1]=i,c[i][i]=1; for(i=1;i<=N;i++) for(j=1;j<=N;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%Mod; for(i=1;i<=N;i++) scanf("%d",&a[i]); for(i=N;i>=1;i--){ if(a[i]>0&&i+a[i]<=N){ for(j=i+a[i];j<=N;j++){ (dp[i]+=(ll)c[j-i-1][a[i]-1]*(1+sum[j+1])%Mod)%=Mod; //这里的1是指只有一个段的情况 printf("%d %d ", c[j-i-1][a[i]-1],(1+sum[j+1])); } } sum[i]=(sum[i+1]+dp[i])%Mod; // printf("%d ", sum[i]); } printf("%d ",sum[4]); return 0; } // #include <iostream> // #include <cstdio> // #include <cstdlib> // #include <cstring> // #include <cmath> // #define qwq(i,j,k) for(int i=j; i<k; ++i) // #define qeq(i,j,k) for(int i=j; i<=k; ++i) // #define mem(a,b) memset(a, b, sizeof(a)) // using namespace std; // typedef long long ll; // const int mx = 1e5+5; // const int maxn = 3e3+5; // const int inf= 0x3f3f3f3f; // // const ll mod = 1e9+7; // const ll INF = 1e18+100; // int n, m; // int cas, tol, T; // ll C[maxn][maxn]; // ll fac[mx]; //i! // ll inv[mx]; //i!在取模mod的情况下的逆元 // // ll fpow(ll a, ll b) { // // ll ans = 1; // // while(b) { // // if(b & 1) // // ans = ans * a % mod; // // a = a * a % mod; // // b >>= 1; // // } // // return ans; // // } // const ll mod=998244353; // void handle() { // // fac[0] = 1; // // for(int i=1; i<=mx; ++i) { // // fac[i] = fac[i-1]*i%mod; //阶乘的表 // // } // // inv[mx] = fpow(fac[mx], mod-2); // // for(int i=mx-1; i>=1; --i) { // // inv[i] = inv[i+1] * (i+1) % mod; // // } // C[0][0] = 1; // C[1][0] = C[1][1] = 1; // for(int i=2; i<maxn; ++i) { // for(int j=0; j<=i; ++j) { // C[i][j] = j==0 ? 1 : (C[i-1][j]%mod+C[i-1][j-1]%mod)%mod; // } // } // } // ll a[maxn]; // ll b[maxn]; // ll ans; // int main() { // //打表O(N^2) n 1e3左右 // handle(); // // for(int i=1; i<=10; ++i) { // // for(int j=0; j<=i; ++j) { // // printf("C[%d][%d] = %lld ", i, j, C[i][j]); // // } // // } // ans=0; // scanf("%d",&n); // for(int i=1; i<=n; i++){ // cin>>a[i]; // } // for(int i=1; i<=n; i++){ // if(a[i]>0 && a[i]+i<=n){ // b[i] = C[n-i][ a[i] ]; // } // } // for(int i=n-1; i>=1; i--){ // if(b[i]!=0){ // ll sum=0; // for(int j=n-1; j>=i+a[i]+1; j--){ // // if(a[j]>0 && a[j]+j<=n){ // b[i] += b[j]; // // } // // if(i==4) printf("b[4]=%lld ", b[i]); // } // // b[i] = (b[i]%mod + b[ i+a[i]+1 ]%mod)%mod; // ans = (ans+b[i])%mod; // } // } // printf("%d ", b[2]); // cout<<ans<<endl; // return 0; // }