【NOIP2017提高A组集训10.22】友谊

Description

Flowey 是一朵能够通过友谊颗粒传播LOVE 的小花.它的友谊颗粒分为两种,
圆粒的和皱粒的,它们依次排列组成了一个长度为2m 的序列.对于一个友谊颗
粒的序列,如果存在1<=i

Solution

这道题60分很好打,设f[i][j][k]为做到第i个,偶数的圆粒和皱粒的个数,然后转移,注意要看到只有前偶后奇才能转移就很简单了。
我们发现,最麻烦的东西就是上面的限制。
要要求数量不超过2n,那么我们就在前面强制放n个偶数(圆粒+皱粒=n),然后只要后面失配的奇数可以被前面的这个n匹配完,那么就合法。
因为我们是一奇一偶的加进来的,所以我们偶数的个数一定不会减少(进来一对奇偶,匹不匹配成功偶数总数都为n),那么就是圆粒还是皱粒的问题了,设f[i][j]表示做到第i个偶数圆粒为j个,那么偶数皱粒为n-j个,所以就可以像60分一样强行转移。
但是我们发现会算重,有很多情况都会算重。
但是我们发现当j=0的时候是不会算重的,因为这时的序列是唯一确定的,所以我们还要多记录一维表示是否已经达到过0。
但是我们可以发现第一个奇数是不会被前面的偶数匹配到的,所以这个奇数和另一个偶数的颜色随意,最后答案*4

Code

#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define min(a,b) (a
using namespace std;
typedef long long ll;
const int maxn=3007;
ll i,j,k,l,t,n,m,ans,mo,u,v;
ll f[maxn][maxn][2];
int main(){
    freopen("friend.in","r",stdin);
    freopen("friend.out","w",stdout);
    scanf("%lld%lld%lld",&n,&m,&mo);n--,m--;
    fo(i,1,n)f[0][i][0]=1;f[0][0][1]=1;
    fo(i,0,m-1){
        fo(j,0,n){
            f[i+1][j][0]=(f[i+1][j][0]+2*f[i][j][0])%mo;
            f[i+1][j][1]=(f[i+1][j][1]+2*f[i][j][1])%mo;
            f[i+1][j+1][0]=(f[i+1][j+1][0]+f[i][j][0])%mo;
            f[i+1][j+1][1]=(f[i+1][j+1][1]+f[i][j][1])%mo;
            if(j){
                if(j==1)f[i+1][j-1][1]=(f[i+1][j-1][1]+f[i][j][1]+
                f[i][j][0])%mo;
                else f[i+1][j-1][1]=(f[i+1][j-1][1]+f[i][j][1])%mo
                ,f[i+1][j-1][0]=(f[i+1][j-1][0]+f[i][j][0])%mo;
            }
        }
    }
    fo(i,0,n)ans=(ans+f[m][i][1])%mo;
    printf("%lld\n",ans*4%mo);
}

你可能感兴趣的:(友谊,NOIP,DP,算重,动态规划,noip,DP)