IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> CF1567C——两种解法:隔离的思想、状压dp;并拓展到一般情况 -> 正文阅读

[C++知识库]CF1567C——两种解法:隔离的思想、状压dp;并拓展到一般情况

题意:定义了另一种加法,把加法进位的位置从i+1变为i+2。求满足x+y=n(x,y)个数,x和y是正整数,1000组数据,n<=1e9

一道让人思维开阔的好题。

法一:隔离的思想。既然进位位置是i+2,那么i、i+2、i+4……和i+1、i+3、……是互不干扰的。于是我们惊奇地发现,按位置下标i模2的剩余类内部,进行的是正常的加法。因此我们按位置下标的奇偶,分出两个数,按乘法原理组合出方案即可。比如n=114514,分出141和154,其中一个方案是071+070=141,004+150=154,则007014+017500=114514。高位补0是为了一致性,奇数下标的数字用粗体标出。

但这样算出的方案是含有(n,0)和(0,n)这两种非法方案的,因此还要减2。

拓展:若进位位置改成i+x,则按位置下标模x的剩余类来分出x个整数,进行乘法原理即可~

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)

const int N = 3e5 + 5;

int n;

void dbg(){puts("");}
template<typename T, typename... R>void dbg(const T &f, const R &... r) {
    cout << f << " ";
    dbg(r...);
}
template<typename Type>inline void read(Type &xx){
    Type f = 1;char ch;xx = 0;
    for(ch = getchar();ch < '0' || ch > '9';ch = getchar()) if(ch == '-') f = -1;
    for(;ch >= '0' && ch <= '9';ch = getchar()) xx = xx * 10 + ch - '0';
    xx *= f;
}

int main(int argc, char** argv) {
    int T;read(T);
    while(T--){
        read(n);
        vector<int> v1,v2;
        for(int i = 0;n;++i,n /= 10){
            if(i&1) v2.push_back(n%10);
            else v1.push_back(n%10);
        }
        reverse(v1.begin(),v1.end());
        reverse(v2.begin(),v2.end());
        int n1 = 0,n2 = 0;
        for(int v: v1) n1 = 10*n1+v;
        for(int v: v2) n2 = 10*n2+v;
        printf("%d\n",(n1+1)*(n2+1)-2);
    }
    return 0;
}

法二:状压dp。官方题解讲得很晦涩,但它的思想很简单。还是拿n=114514举例。首先,我们假设已经求出了11451的答案,然后看能不能转移,因此状态需要记录i,表示当前数字是从位置i到最高位(下标为len-1)的。但这不够,因为114514可能向11451的十位进位,所以状态需要记录数字的十位(下标为1)是否有来自低位的进位。因为114514的十位就是11451的个位,即11451的个位的进位情况,必须和114514的十位的进位情况保持同步,所以状态还需要记录数字的个位(下标为0)是否有进位。

总结一下,我们引入了dp[i][j],而进位情况同步的要求引入了状态kjk分别表示当前数字的十位和个位是否有来自低位的进位。

为了方便,我们先允许非负整数,再减去(n,0)和(0,n)这两种非法方案。所以答案是dp[0][0][0]-2

边界:dp[len-1][0][k]=d[dl-1]+k,既然只有1位,那么十位必须是不进位才有方案。

转移:分11451的十位有和没有进位来讨论。(d[i]+1-k)*dp[i+1][0][j] + (9+k-d[i])*dp[i+1][1][j]

拓展:若进位位置改成i+x,则就是一个纯正的状压dp。个位以外的所有进位情况都是保持同步。具体参照”拓展“的代码(对拍已通过,可以放心食用~)。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)

const int N = 3e5 + 5;

int n,dp[13][2][2];

void dbg(){puts("");}
template<typename T, typename... R>void dbg(const T &f, const R &... r) {
    cout << f << " ";
    dbg(r...);
}
template<typename Type>inline void read(Type &xx){
    Type f = 1;char ch;xx = 0;
    for(ch = getchar();ch < '0' || ch > '9';ch = getchar()) if(ch == '-') f = -1;
    for(;ch >= '0' && ch <= '9';ch = getchar()) xx = xx * 10 + ch - '0';
    xx *= f;
}

int main(int argc, char** argv) {
    int T;read(T);
    while(T--){
        read(n);
        memset(dp,0,sizeof dp);
        vector<int> d;
        for(;n;n /= 10) d.push_back(n%10);
        int dl = d.size();
        dp[dl-1][0][0] = d[dl-1]+1;
        dp[dl-1][0][1] = d[dl-1];
        dwn(i,dl-2,0){
            rep(j,0,1){
                rep(k,0,1){
                    dp[i][j][k] = (d[i]+1-k)*dp[i+1][0][j] + (9+k-d[i])*dp[i+1][1][j];
                }
            }
        }
        // rep(i,0,dl-1) rep(j,0,1) rep(k,0,1) cout<<dp[i][j][k]<<" \n"[j&&k];//
        printf("%d\n",dp[0][0][0]-2);
    }
    return 0;
}
拓展
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)

const int N = 3e5 + 5;

int n,dp[13][32];

void dbg(){puts("");}
template<typename T, typename... R>void dbg(const T &f, const R &... r) {
    cout << f << " ";
    dbg(r...);
}
template<typename Type>inline void read(Type &xx){
    Type f = 1;char ch;xx = 0;
    for(ch = getchar();ch < '0' || ch > '9';ch = getchar()) if(ch == '-') f = -1;
    for(;ch >= '0' && ch <= '9';ch = getchar()) xx = xx * 10 + ch - '0';
    xx *= f;
}

int solve1(int n,int pos){
    vector<int> v[pos];
    for(int i = 0;n;++i,n /= 10){
        v[i%pos].push_back(n%10);
    }
    re_(i,0,pos) reverse(v[i].begin(),v[i].end());
    int ans = 1;
    re_(i,0,pos){
        int x = 0;
        for(int va: v[i]) x = 10*x+va;
        ans *= x+1;
    }
    return ans-2;
}

int solve2(int n,int pos){
    memset(dp,0,sizeof dp);
    vector<int> d;
    for(;n;n /= 10) d.push_back(n%10);
    int dl = d.size();
    dp[dl-1][0] = d[dl-1]+1;
    dp[dl-1][1] = d[dl-1];
    dwn(i,dl-2,0){
        re_(j,0,1<<pos){
            int k = j&1;
            dp[i][j] = (d[i]+1-k)*dp[i+1][j>>1] + (9+k-d[i])*dp[i+1][(1<<(pos-1))|(j>>1)];
        }
    }
    // rep(i,0,dl-1) re_(j,0,1<<pos) cout<<dp[i][j]<<" \n"[j+1==(1<<pos)];//
    return dp[0][0]-2;
}

int main(int argc, char** argv) {
    int T;read(T);
    while(T--){
        read(n);
        rep(i,2,5){
            int a1 = solve1(n,i),a2 = solve2(n,i);
            printf("%d %d\n",a1,a2);
            assert(a1 == a2);
        }
    }
    return 0;
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-22 14:29:00  更:2021-09-22 14:30:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 22:35:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码