链接:https://ac.nowcoder.com/acm/contest/7412/I
来源:牛客网
题目描述
有一个n×m的网格地图,每个点有个值aij,现在牛牛要从(1,1)走到(n,m),他可以往右边或者往下走,每次到一个点会获得当前的点权值,并将权值和mod 1e4 + 7,当牛牛从不同方式走到(n,m)的时候能获得多少种权值和?
输入描述:
第一行输入正整数n,m(n,m≤100)n,m(n,m leq 100)n,m(n,m≤100)
接下来 nnn 行每行有 mmm 个正整数,分别代表aija_{ij}aij(aij≤109)(a_{ij}leq 10^9)(aij≤109)
输出描述:
输出一行,表示到(n,m)点的时候的权值和种数
示例1
输入
2 2 1 1 2 2
输出
2
说明
有1+1+2和1+2+2两种
解法:每个点aij只可能由aij -1、ai-1j转移过来,dp[ i ][ j ][ (k + a[ i ][ j ])%mod ] = dp[ i ][ j - 1 ][ k ] | dp[ i - 1 ][ j ][ k ]
代码:
#include<bits/stdc++.h> #define ll long long using namespace std; const int mod=1e4+7; int n,m; int a[105][105]; bool dp[105][105][mod+5]; int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>a[i][j]; a[i][j]%=mod; } } dp[1][1][a[1][1]]=1; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(i==1&&j==1) continue; for(int k=0;k<mod;k++){ dp[i][j][(a[i][j]+k)%mod]|=dp[i][j-1][k]; dp[i][j][(a[i][j]+k)%mod]|=dp[i-1][j][k]; } } } int ans=0; for(int k=0;k<mod;k++) ans+=dp[n][m][k]; cout<<ans<<endl; }
用bitset的写法:
#include<bits/stdc++.h> #define ll long long using namespace std; const int mod=1e4+7; int n,m; int a[105][105]; bitset<mod>dp[105][105]; int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>a[i][j]; a[i][j]%=mod; } } dp[0][1]=1;dp[1][0]=1; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ bitset<mod> cnt1=(dp[i][j-1]<<a[i][j])|(dp[i][j-1]>>(mod-a[i][j])); bitset<mod> cnt2=(dp[i-1][j]<<a[i][j])|(dp[i-1][j]>>(mod-a[i][j])); dp[i][j]=cnt1|cnt2; } } cout<<dp[n][m].count()<<endl; }