Codeforces Round #742 (Div. 2)--C
原题链接: Carrying Conundrum
思维写法
思路:因为题目定义的进位是往前两位进位,也就是奇数位进奇数位,偶数位进偶数位,
进而可以发现奇数位和偶数位互不影响。我们把目标数n的奇偶位分开组成新的数:比如
n=abcd ,n1=ac ,n2=bd。正常运算下凑一个数x的方式数是x+1,最后减去n1和n2是0的情况
最终答案就是:(n1+1)*(n2+1)-2 。
void solve(){
ll n;
cin>>n;
ll a=0,b=0; int cnt=1; ll k=1;
while(k<=n) k*=10,cnt++;k/=10;cnt--;
while(cnt){
if(cnt%2==1)
a=a*10+n/k;
else b=b*10+n/k;
n=n%k; k/=10;
cnt--;
}
cout<<(a+1)*(b+1)-2<<endl;
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
动态规划写法
- 设状态转移方程:
\(dp[i][l][m]\) 表示:数字x的第i位是否向前进位(j=1/0),是否由更小的位进位(k=1/0) - 设\(x=x1+x2\),每一位的值有3种来源\(x1,x2\),更小的位进位。暴力枚举三个值
- 最后减去 x1,0;0,x2; 这两种情况
ll dp[10][2][2];
void solve(){
string s;
cin>>s;
int n=s.size();
memset(dp,0,sizeof dp);
dp[n][0][0]=1;
for (int i=n-1;i>=0;--i)
for (int j=0;j<10;++j)
for (int k=0;k<10;++k)
for (int l=0;l<2;++l)
for (int m=0;m<2;++m)
if ((j+k+l)%10==s[i]-'0')
dp[i][m][(j+k+l)/10]+=dp[i+1][l][m];
cout<<dp[0][0][0]-2<<endl;
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}