Codeforces Round #742 (Div. 2)--C

原题链接: Carrying Conundrum
image

思维写法

思路:因为题目定义的进位是往前两位进位,也就是奇数位进奇数位,偶数位进偶数位,
进而可以发现奇数位和偶数位互不影响。我们把目标数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;
}
posted @ 2021-09-06 17:22  qingyanng  阅读(50)  评论(0编辑  收藏  举报