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 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> 暑假第三周学习笔记 -> 正文阅读

[Python知识库]暑假第三周学习笔记

周一

今天的主要精力在学python

感觉一些事情上还是没有达到自己的期望

但大学还是抱着学习的心态去努力汲取知识

做一块海绵 用这宝贵时光努力学习成长

周二

今天早上跑了步,出了很多汗,整个人都舒服很多

坚持锻炼

最近今天有点摸鱼,回归猛肝的状态

搞起

P3522 [POI2011]TEM-Temperature(单调队列)

这道题首先发现要维护之前的一个区间的最大值

而这个区间又是连续的,左右端点只会增加,就用单调队列

注意单调队列里面存的值是区间的部分值,所以更新的时候要注意不一定是队头的来更新

交上去WA了

因为是最大值,所以我就写了一个单调递减的单调队列,以往我都这么写

但是这道题不行,因为相等的时候元素不能删,这道题更新答案的时候和其位置有关,相等的时候并不是等价的

以前更新答案的时候是f(x)的形式,x同f(x)就同,而这题不一样。

#include<bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

const int N = 1e6 + 10;
int dp[N], a[N], b[N], q[N], n;

int main()
{
    scanf("%d", &n);
    _for(i, 1, n) scanf("%d%d", &a[i], &b[i]);

    int l = 1, r = 1, ans = 1, first = 1;
    dp[1] = q[1] = 1;
    _for(i, 2, n)
    {
        while(l <= r && a[q[l]] > b[i])
        {
            l++;
            if(l <= r) first = q[l];
            else first = i;
        }

        dp[i] = i - first + 1;
        ans = max(ans, dp[i]);

        while(l <= r && a[q[r]] < a[i]) r--;
        q[++r] = i;
    }

    printf("%d\n", ans);

    return 0;
}

P4544 [USACO10NOV]Buying Feed G(单调队列优化dp)

很容易想到dp[i][j]表示前i个坐标j吨饲料的最小花费

一开始想枚举之前所有的坐标,来转移,发现这样很慢

直接前i个,枚举前面一个买或不买,买的话买多少。也就是说存在不买的情况。?

可以写出dp[i][j] = min(dp[i-1][j-t] * (x[i] - x[i - 1]) + t * c[i - 1])

0 <= t <= f[i - 1]

这样会超时,考虑单调队列优化

三层循环,i, j, t,显然优化第三层

然后我就卡住了,发现这样很难搞,我就把式子换了一下

dp[i-1][p] + j* j * (x[i] - x[i - 1]) + j * c[i - 1]?-?p?* c[i - 1]

发现j* j * (x[i] - x[i - 1]) + j * c[i - 1]对于当前的dp[i][j]来说是定值

而i定时,dp[i - 1][p] - p * c[i - 1]这个东西是可以用单调队列优化的

因为p有范围,且值只与p本身有关(i定值),与变化的j无关

#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

typedef long long ll;
const int N = 500 + 10;
const int M = 1e4 + 10;
struct node { ll x, f, c; };
vector<node> ve;
int q[M], k, e, n;
ll dp[N][M];

bool cmp(node a, node b)
{
    return a.x < b.x;
}

ll val(int i, int p)
{
    return dp[i - 1][p] - p * ve[i - 1].c;
}

int main()
{
    scanf("%d%d%d", &k, &e, &n);
    _for(i, 1, n)
    {
        ll x, f, c;
        scanf("%lld%lld%lld", &x, &f, &c);
        ve.push_back(node{x, f, c});
    }
    ve.push_back(node{e, 0, 0});
    sort(ve.begin(), ve.end(), cmp);

     _for(j, 1, k) dp[0][j] = 1e18;
    rep(i, 1, ve.size())
    {
        _for(j, 0, k) dp[i][j] = 1e18;

        int l = 1, r = 0;
        _for(j, 0, k)
        {
            while(l <= r && val(i, q[r]) >= val(i, j)) r--;
            q[++r] = j;

            while(l <= r && j - ve[i - 1].f > q[l]) l++;
            dp[i][j] = min(dp[i][j], j * j * (ve[i].x - ve[i - 1].x) + j * ve[i - 1].c + val(i, q[l]));
        }
    }
    printf("%lld\n", dp[ve.size() - 1][k]);

    return 0;
}

P3572 [POI2014]PTA-Little Bird(单调队列)

逐渐进入状态

这题依然是单调队列

因为取最小的是dp值,所以按照dp值的大小来构造单调队列

这里的高度要注意

首先dp值小但高度更低也没有关系,这样结果至少不会更差

做单调队列的题目时要考虑是否可以相等的问题

这道题相等的时候要格外考虑,dp值相同时就按照高度

如果dp值相同,高度小,又在更左边,那就出队

此外,写单调队列先初始化,先把第一个点入队,再弄

#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

const int N = 1e6 + 10;
int h[N], dp[N], q[N], n, m, k;

int main()
{
    scanf("%d", &n);
    _for(i, 1, n) scanf("%d", &h[i]);

    scanf("%d", &m);
    while(m--)
    {
        scanf("%d", &k);

        int l = 1, r = 1;
        q[1] = 1; dp[1] = 0;
        _for(i, 2, n)
        {
            while(l <= r && q[l] < i - k) l++;
            dp[i] = dp[q[l]] + (h[q[l]] <= h[i]);

            while(l <= r && (dp[q[r]] > dp[i] || dp[q[r]] == dp[i] && h[q[r]] < h[i])) r--;
            q[++r] = i;
        }
        printf("%d\n", dp[n]);
    }

    return 0;
}

P3089 [USACO13NOV]Pogo-Cow S(状态设计与枚举顺序)

这题是看题解的

首先这个状态设计我就没想到,dp[j][i]表示从j跳到i的最大值

感觉就挺突然的………………还是太菜了

转移方程很好写 dp[j][i] = max(p[i] + dp[k][j]) = p[i] + max(dp[k][j])
考虑怎么优化,一开始想单调队列优化k,发现不行

因为在j移动的时候,dp[k][j]和j有关。这个值应该和移动j无关才行

然后我就卡住了

看了题解,真的妙,按照常规思维是先枚举i后枚举j

这里改成先枚举j后枚举i,这样子dp[k][j]的时候,就与移动i无关了

可以发现,固定j的时候,i逐渐增大,可以用来转移的dp[k][j]只会增加不会减少

因此就用一个变量来维护就行了

这题还要换个方向,这时其实很容易,把整个数组翻转一下再做一次就行了

#include <bits/stdc++.h>
#define x first
#define p second
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

const int N = 1e3 + 10;
int dp[N][N], ans, n;
pair<int, int> a[N];

void solve()
{
    _for(j, 1, n)
    {
        dp[j][j] = a[j].p;
        int mx = dp[j][j], k = j;
        _for(i, j + 1, n)
        {
            while(k - 1 >= 1 && abs(a[k - 1].x - a[j].x) <= abs(a[i].x - a[j].x)) mx = max(mx, dp[--k][j]);
            dp[j][i] = a[i].p + mx;
        }
    }

    _for(j, 1, n)
        _for(i, j, n)
            ans = max(ans, dp[j][i]);
}

int main()
{
    scanf("%d", &n);
    _for(i, 1, n) scanf("%d%d", &a[i].x, &a[i].p);
    sort(a + 1, a + n + 1);

    solve();
    reverse(a + 1, a + n + 1);
    solve();
    printf("%d\n", ans);

    return 0;
}

?D - Meaningless Sequence(数位dp)

接下来刷几道数位dp

数位dp无非是问一个区间内有多少个符合题目条件的数

每个数都有个值,如果问个数则值为1,问其他的看题目

这道题可以发现每个数的值就是c^(1的个数)

数位dp套模板就行

模板还是要深刻理解比较好。无非是lead 和 limit 记忆化搜索

这道题前导0,是否为第一位等无所谓

所以不需要lead

#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

typedef long long ll;
const int N = 3000 + 10;
const int mod = 1e9 + 7;
ll dp[N][N], c;
int len;
string a;

int add(int a, int b) { return (a + b) % mod; }
int mul(int a, int b) { return 1LL * a * b % mod; }

int binpow(int a, int b)
{
    int res = 1;
    for(; b; b >>= 1)
    {
        if(b & 1) res = mul(res, a);
        a = mul(a, a);
    }
    return res;
}

int dfs(int pos, int sum, int limit)
{
    if(pos >= len) return binpow(c, sum);
    if(!limit && dp[pos][sum] != -1) return dp[pos][sum];
    ll res = 0, mx = limit ? (a[pos] - '0') : 1;
    _for(i, 0, mx) res = add(res, dfs(pos + 1, sum + i, i == mx && limit));
    if(!limit) dp[pos][sum] = res;
    return res;
}

int main()
{
    cin >> a >> c;
    len = a.size();
    memset(dp, -1, sizeof dp);
    printf("%d\n", dfs(0, 0, 1));
    return 0;
}

P4999 烦人的数学作业(数位dp)

挺水的。这道题的值是每个数字之和

#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

typedef long long ll;
const int mod = 1e9 + 7;
int dp[25][200], a[25], len;

int add(int a, int b) { return (a + b) % mod; }
int mul(int a, int b) { return 1LL * a * b % mod; }

int dfs(int pos, int sum, int limit)
{
    if(pos > len) return sum;
    if(!limit && dp[pos][sum] != -1) return dp[pos][sum];
    int res = 0, mx = limit ? a[len - pos + 1] : 9;
    _for(i, 0, mx) res = add(res, dfs(pos + 1, sum + i, i == mx && limit));
    if(!limit) dp[pos][sum] = res;
    return res;
}

int solve(ll x)
{
    len = 0;
    while(x) a[++len] = x % 10, x /= 10;
    memset(dp, -1, sizeof dp);
    return dfs(1, 0, 1);
}

int main()
{
    int T; scanf("%d", &T);
    while(T--)
    {
        ll l, r;
        scanf("%lld%lld", &l, &r);
        printf("%d\n", (solve(r) - solve(l - 1) + mod) % mod);
    }
    return 0;
}

P4124 [CQOI2016]手机号码(数位dp)

一样套模板,只是复杂了一点

注意要特判一下

#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

typedef long long ll;
ll dp[25][15][15][2][2][2], a[25], len;

ll dfs(int pos, int pre1, int pre2, int have4, int have8, int ans, int lead, int limit)
{
    if(pos > len) return ans;
    if(!limit && !lead && dp[pos][pre1][pre2][have4][have8][ans] != -1) return dp[pos][pre1][pre2][have4][have8][ans];
    ll res = 0, mx = limit ? a[len - pos + 1] : 9;
    _for(i, 0, mx)
    {
        if(!i && lead || i == 4 && have8 || i == 8 && have4) continue;
        res += dfs(pos + 1, i, pre1, have4 | i == 4, have8 | i == 8, ans | (i == pre1 && pre1 == pre2), 0, i == mx && limit);
    }
    if(!limit && !lead) dp[pos][pre1][pre2][have4][have8][ans] = res;
    return res;
}

ll solve(ll x)
{
    len = 0;
    while(x) a[++len] = x % 10, x /= 10;
    memset(dp, -1, sizeof dp);
    return dfs(1, 10, 10, 0, 0, 0, 1, 1);
}

int main()
{
    ll l, r;
    scanf("%lld%lld", &l, &r);
    if(l == 1e10) printf("%lld\n", solve(r));
    else printf("%lld\n", solve(r) - solve(l - 1));
    return 0;
}

P2606 [ZJOI2010]排列计数(dp统计方案数)

首先把这道题转化到图上

有多少种小根堆的方案

用dp[u]表示以u为根节点的子树有多少种方案

这时我们把最小的数放在u

左子树放一部分,数目是左子树的节点数,剩下的放右子树

这样dp[u] = C(size[u] - 1, size[l]) * dp[l] * dp[r]

用dfs遍历就行 注意边界条件是当这个点为叶子的时候返回1

这里有坑,就是模数可能比较小,可能求组合数的时候n n - m是模数的倍数

这样就不能用费马小定理。解决方法是Lucas 定理

不用考虑具体怎么放,总之就是当前数最小的放在根,然后递归下去

#include <bits/stdc++.h>
#define l(k) (k << 1)
#define r(k) (k << 1 | 1)
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

const int N = 1e6 + 10;
int fac[N], siz[N], n, mod;

int add(int a, int b) { return (a + b) % mod; }
int mul(int a, int b) { return 1LL * a * b % mod; }

int binpow(int a, int b)
{
    int res = 1;
    for(; b; b >>= 1)
    {
        if(b & 1) res = mul(res, a);
        a = mul(a, a);
    }
    return res;
}

int inv(int x) { return binpow(x, mod - 2); }

void init(int u)
{
    siz[u] = 1;
    if(l(u) <= n) init(l(u)), siz[u] += siz[l(u)];
    if(r(u) <= n) init(r(u)), siz[u] += siz[r(u)];
}

int cal(int n, int m)
{
    if(m > n) return 0;
    return mul(fac[n], mul(inv(fac[m]), inv(fac[n - m])));
}

int C(int n, int m)
{
    if(m == 0) return 1;
    return mul(cal(n % mod, m % mod), C(n / mod, m / mod));
}

int dfs(int u)
{
    if(l(u) > n) return 1;
    return mul(mul(C(siz[u] - 1, siz[l(u)]), dfs(l(u))), dfs(r(u)));
}

int main()
{
    scanf("%d%d", &n, &mod);
    fac[0] = 1; _for(i, 1, n) fac[i] = mul(fac[i - 1], i);
    init(1);
    printf("%d\n", dfs(1));
    return 0;
}

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章           查看所有文章
加:2021-07-14 00:20:01  更:2021-07-14 00:20:26 
 
开发: 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年5日历 -2024/5/4 18:02:12-

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