出题人的题解还是讲的挺清晰的,emm,为了方便大家理解出题人的题解我解说一下..思路大概就是线性dp+差分,做这个题目的时候没有思路大概就是dp的魅力吧!
下面讲讲怎么做?
题目要求起点和终点同时不能出现两次,用差分思想就是分配括号,相同的括号不能出现两次在同一个地方出现两次,并且括号一定要合法..什么是合法呢?就是(的数量一定大于或者等于)的,不然肯定不行啊..
出题人聚聚说的,我觉得它写的超级棒~
对于每个每个点有4种放置:
放置1:(
放置2:)
放置3:(、)
放置4:什么都不放
然后建立状态dp[i][j]表示到第i个位子,(比)多了j个,使得前i个都等于m?多了多少个(就相当于这个位子可以多少次+1.
先考虑初始赋值..
假如起始位子是a[i]=m-1,dp[1][1]//(比)多1,或者dp[1][0] (和)在同一个位子.都是符合条件的,代码如下:
if(a[i]==m-1) {dp[1][0]=1;dp[1][1]=1;}
假如起始位子是a[i]=m,就dp[1][0]//不放括号,是符合条件的,代码如下:
if(a[i]==m) dp[1][0]=1;
然后考虑状态转移..
位于当前位子的值为ai;
它假如能转移那么它的值只能是有dp[i-1][m-a[i]-1]/dp[i-1][m-a[i]]转移过来,代表这个地方放(/(),或者这个地方放)/或者什么都不放..当然假如这个地方本身>m了,那就没有方案使得成立了..如此推理转态转移就非常好写了..
下面我贴一下转态转移的代码,清结合我说的看一下.
int flag=0; for(int i=1;i<=n;i++) if(a[i]>m) flag=1; if(flag) cout<<0<<endl; else { for(int i=2;i<=n;i++) { dp[i][m-a[i]]+=dp[i-1][m-a[i]-1];//自己本身+( dp[i][m-a[i]-1]+=dp[i-1][m-a[i]-1]*(m-a[i]);//自己本身+() dp[i][m-a[i]]+=dp[i-1][m-a[i]];//什么都不加.. dp[i][m-a[i]-1]+=dp[i-1][m-a[i]]*(m-a[i]);//加个) } }
下面贴一下ac代码:
#include<bits/stdc++.h> #define ios ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0) #define pb push_back #define inf 132913423039 typedef long long ll; const ll mod=998244355; const ll N=2e3+5; const ll M=2e4+5; const double eps=1e-7; using namespace std; ll gcd(ll a,ll b) {return b==0?a:gcd(b,a%b);} ll lcm(ll a,ll b) { return a*b/gcd(a,b); } ll qp(ll a,ll b, ll p){ll ans = 1;while(b){if(b&1){ans = (ans*a)%p;--b;}a = (a*a)%p;b >>= 1;}return ans%p;} ll Inv(ll x) { return qp(x,mod-2,mod);} ll C(ll n,ll m){if (m>n) return 0;ll ans = 1;for (int i = 1; i <= m; ++i) ans=ans*Inv(i)%mod*(n-i+1)%mod;return ans%mod;} ll dp[M][N]; ll a[M]; int main()//要你把n个数->m.. { ios; ll n,m; cin>>n>>m; for(ll i=1;i<=n;i++) cin>>a[i]; ll flag=0; for(int i=1;i<=n;i++) if(a[i]>m) flag=1; if(a[1]==m-1) {dp[1][0]=1;dp[1][1]=1;} if(a[1]==m) dp[1][0]=1; if(flag) cout<<0<<endl; else { for(int i=2;i<=n;i++) { dp[i][m-a[i]]=(dp[i-1][m-a[i]-1])%mod;//自己本身+( dp[i][m-a[i]-1]=(dp[i-1][m-a[i]-1]*(m-a[i]))%mod;//自己本身+() dp[i][m-a[i]]=(dp[i][m-a[i]]+dp[i-1][m-a[i]])%mod;//什么都不加.. dp[i][m-a[i]-1]=(dp[i][m-a[i]-1]+dp[i-1][m-a[i]]*(m-a[i]))%mod;//加个) } } cout<<dp[n][0]<<endl; return 0; }