CSP-S 2019--에미야네 오늘의 밥--DP+사고

1686 단어 가방 문제DP
문제풀이: 본 문제는 주로 DP+사유를 고찰한다.간략한 제목의 뜻: 하나의 행렬은 줄마다 하나의 노드만 선택하도록 요구한다. 열마다 선택한 노드는 모든 선택한 노드의 절반을 초과할 수 없다. 선택하지 않을 수 없다. 각 노드의 선택 방안 수를 제시하고 전체 방안 수를 구한다.1. DP+ 사유: (1).각 열에서 선택한 노드를 유지하는 것은 복잡도가 너무 커서 안 될 것이다. 그래서 각 열이 절반을 넘지 않는 것을 고려하지 않고 총수를 구한 다음에 비합법적인 방안수를 줄이고 역방향 사고 전환 문제를 응용한다.(2).dp[i][j][k]dp[i][j][k]dp[i][j][k]를 설정하면 전 ii행에서 jj개 노드를 선택하고 현재 매거된 열에서 kk개 노드를 선택하는 방안수를 나타낸다. 그러나 이렇게 복잡도가 높기 때문에 최적화해야 한다.제한 조건 k>⌊j/2⌋k>⌊j/2⌋k>⌊j/2⌋에서 2k+n-j>n2k+n-j>n2k+n-j>n을 획득하면 무용 상태를 제거할 수 있습니다.전환 방정식:
    dp[j][k]=(dp[j][k]+dp[j-1][k]*(sum[j]-a[j][i]))%mod;
    dp[j][k+1]=(dp[j][k+1]+dp[j-1][k])%mod;
    dp[j][k+2]=(dp[j][k+2]+dp[j-1][k]*a[j][i])%mod;

코드는 다음과 같습니다.
#include
#include
#include
#include
using namespace std;
long long dp[201][3001],a[201][3001],sum[2001];
long long ans=1,n,m;
int mod=998244353;
int main()
{
	ios::sync_with_stdio(false);
    cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>a[i][j];
			sum[i]=(sum[i]+a[i][j])%mod;
		}
		ans=(ans*(sum[i]+1))%mod;
	} 
	ans=(ans+mod-1)%mod;
	for(int i=1;i<=m;i++)
    {
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        for(int j=1;j<=n;j++)
        for(int k=0;k<=2*(j-1);k++)
        {
            dp[j][k]=(dp[j][k]+dp[j-1][k]*(sum[j]-a[j][i]))%mod;
            dp[j][k+1]=(dp[j][k+1]+dp[j-1][k])%mod;
            dp[j][k+2]=(dp[j][k+2]+dp[j-1][k]*a[j][i])%mod;
        }
        for(int j=n+1;j<=2*n;j++)
        ans=(ans+mod-dp[n][j])%mod;
    }
    printf("%lld",ans);
	return 0;
}

좋은 웹페이지 즐겨찾기