首页 > 其他分享 >AtCoder Beginner Contest 288(D,E,F)

AtCoder Beginner Contest 288(D,E,F)

时间:2023-05-31 19:24:40浏览次数:59  
标签:AtCoder Beginner int sum long 288 include dp define

AtCoder Beginner Contest 288(D,E,F)

D(思维)

D

有一个数组,然后有\(q\)次询问,每一次输入一对\(l,r\),我们要判断这一段里面的数是不是好数组

好数组,在进行下面任意次操作后可以把这一段数字都变成\(0\),那么这就是个好数组

操作是选择一个\(i\)和一个\(c\),但是\(i+k-1\)要小于\(r\),我们会把\(i\)到\(i+k-1\)的数都加上\(c\)

这个正解感觉比较难想

我们把那些位置取模一样的加在一起,然后我们判断\(l,r\)这一段\(k\)个取模的结果的和都是一样的,那么就可以成为好数组,反之不然

这个可以这么来理解,可以假如只有一个长度为\(k\)的数组,我们只有这\(k\)个数都是一样的才可以,正好每一个位置都代表着不同的取模,就和上面的解法没有相悖的

至于证明,可以看这 博客

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include<cmath>
#include <unordered_map>
#include <array>
#include <cstring>
using namespace std;
#define int long long 
#define LL long long
#define ios  ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define inf 1e18
#define INF 1e18
#define mem(a,b) memset((a),(b),sizeof(a))
const int maxn=2e5+10;
const int mod=998244353;
int n,k;
int q;
int sum[maxn][14];
int a[maxn];
bool solve()
{
    int l,r;
    cin>>l>>r;
    int p=sum[r][0]-sum[l-1][0];
    for (int i=1;i<k;i++)
    {
        if(sum[r][i]-sum[l-1][i]!=p) return false;
    }
    return true;
}
signed main ()
{
    cin>>n>>k;
    for (int i=1;i<=n;i++)
    {
        cin>>a[i];
        for (int j=0;j<k;j++)
        {
            sum[i][j]=sum[i-1][j];
        }
        sum[i][i%k]+=a[i];
    }
    cin>>q;
    while (q--)
    {
        if(solve())
        {
            cout<<"Yes\n";
        }
        else 
        {
            cout<<"No\n";
        }
    }
    system ("pause");
    return 0;
}

E(dp)

E

大意为一共有\(n\)个物品,每一个物品都有一个原来的价格,我们需要\(m\)个物品,而且,我们每次选择购买那一件物品还需要额外的费用,如果这个物品的编号在剩余还未售出的物品编号中排名为\(k\),那么购买这一件物品的价值为原价加上\(c_k\)

问我们至少得到我们所需的\(m\)件物品的最少费用为多少

最开始想过是贪心,我找到最小的额外费用,然后把那些可以使用这个额外费用的加上去,但是可能我们还得加上那些不需要的,后来想了,不对,极端的想,万一,我所需要的还没有选择,但是因为每次先考虑较低的额外费用导致其他非必须的都购买了,显然不太可行

上面只是我的拙见

下面的解法是\(dp\)

\(dp[i] [j]\)代表从\(1\)到\(i\),我已经购买了\(j\)个物品

如果我还想要再购买一个物品的话,假设额外费用为\(add\),那么状态转移方程如下

\[dp[i][j+1]=dp[i-1][j]+val[i]+add \]

然后我们来分析\(add\)

如果只是我们购买\(i\)是在前面已经购买了\(j\)的情况下,那么在\(1\)到\(i\)剩下就只有\(i-j\)个了,而\(i\)一定是比前面的都大的,所以我们这次的额外费用为\(c_{i-j}\)了

这是我们购买\(i\)在就是在第\(j+1\)次购买,但是如果我们购买\(i\)在第\(j+1\)次购买之前,对比第\(j+1\)次购买的排名一定是更大的,那么我们可以知道\(i\)物品可能存在的额外费用所有比他坐标小于等于的\(c\),但是那些什么时候可以取,最小的\(c\)的坐标取决于目前的\(j+1\),即它作为最新的一次购买

所以我们又可以得到一个状态转移方程

\[dp[i][j+1]=dp[i-1][j]+val[i]+min(add,c[i-j]) \]

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include<cmath>
#include <unordered_map>
#include <array>
#include <cstring>
using namespace std;
#define int long long 
#define LL long long
#define ios  ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define inf 1e18
#define INF 1e18
#define mem(a,b) memset((a),(b),sizeof(a))
const int maxn=2e5+10;
const int mod=998244353;
int n,m;
int val[maxn],add[maxn];
bool must[maxn];
signed main ()
{
    cin>>n>>m;
    for (int i=1;i<=n;i++)
    {
        cin>>val[i];
        must[i]=false;
    }
    for (int i=1;i<=n;i++)
    {
        cin>>add[i];
    }
    for (int i=1;i<=m;i++)
    {
        int x;
        cin>>x;
        must[x]=true;
    }
    vector<int>dp(n+5,inf);
    dp[0]=0;
    for (int i=1;i<=n;i++)
    {
        vector<int>tmp(n+5,inf);
        int w=inf;
        for (int j=0;j<i;j++)
        {
            w=min(w,add[i-j]);
            tmp[j+1]=min(tmp[j+1],dp[j]+val[i]+w);
            if(!must[i])
            {
                tmp[j]=min(tmp[j],dp[j]);
            }
        }
        dp=tmp;
    }
    int ans=*min_element(dp.begin(),dp.end());
    cout<<ans<<"\n";
    system ("pause");
    return 0;
}

F(dp)

F

把一个字符串拆成若干个数,如可以把\(234\)拆成\(34\)和\(5\)这种,我们求的是把这个字符串拆成任可能的大小的数字的乘积

感觉做动态规划的题需要一步一步来

我们先什么都不考虑的话,就是直接暴力的求答案话,可以得到一个状态转移方程

\(f[i]\)是长度为\(i\)的字符串被拆后的乘积

\(dp[i]\)是前\(i\)个不同的拆分的乘积和

\(sum[i]\)是\(f[i]\)的前缀和

\(s[l] [r]\)是从\(l\)到\(r\)这一段形成的数字

\[dp[i]=\sum_{j=0}^{i-1}f[j]\times s[j+1][i] \]

但是我们不太可能去一一枚举\(j\)的,那么我们可以对\(dp\)进行前缀处理,但是\(s[j+1] [i]\)这个还是要一一枚举呀

然后我们可以试着变换一下,

\[dp[i+1]=\sum_{j=0}^{i}f[j] \times s[j+1][i+1] \]

再变化

\[dp[i+1]=\sum_{j=0}^{i}f[j] \times (s[j+1][i]\times10+s[i+1]) \]

发现只有一点不同,那就是累加的最右端,但是我们仔细想一下,在\(i\)的时候,不会出现那样的情况,那么它的贡献是不计的,那么我们也可以忽略。

所以可以再把括号去掉

\[dp[i+1]=10\times\sum_{j=0}^{i}f[j] \times s[j+1][i]+\sum_{j=0}^{i}f[j] \times s[i+1] \]

我们可以发现关系

\[dp[i+1]=10\times dp[i]+sum[i]\times s[i+1] \]

其实也可以理解为把前面所有的情况都往前挪一位,就一个个位给\(s[i]\)

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include<cmath>
#include <unordered_map>
#include <array>
#include <cstring>
using namespace std;
#define int long long 
#define LL long long
#define ios  ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define inf 1e18
#define INF 1e18
#define mem(a,b) memset((a),(b),sizeof(a))
const int maxn=2e5+10;
const int mod=998244353;
int n;
string s;
int dp[maxn];
int sum[maxn];
signed main ()
{
    cin>>n;
    cin>>s;
    s=" "+s;
    dp[0]=0;
    sum[0]=1;
    for (int i=1;i<=n;i++)
    {
        int now=s[i]-'0';
        dp[i]=(dp[i-1]*10+sum[i-1]*now)%mod;
        sum[i]=(sum[i-1]+dp[i])%mod;
    }
    int ans=dp[n];
    cout<<ans<<"\n";
    system ("pause");
    return 0;
}

标签:AtCoder,Beginner,int,sum,long,288,include,dp,define
From: https://www.cnblogs.com/righting/p/17447090.html

相关文章

  • POJ2886线段树 Joseph游戏(单点更新)
    题目:WhoGetstheMostCandies? 题意:1.n个人进行Joseph游戏,游戏共p轮(p为思路:用相对坐标来处理,例如这一轮出局的是p,下一个要+m,则p出局时p+1就变成了p(因为是相对坐标),则下一个人应该是p+m-1,再注意循环和m的正负的处理,不要忘了取模。2.求解原始序号时维护一棵线段树,类似上一题插队......
  • AtCoder Beginner Contest 258 Ex Odd Steps
    洛谷传送门AtCoder传送门不错的矩阵快速幂优化dp练习题。考虑一个朴素dp,\(f_i\)为组成和为\(i\)且用到的数都是奇数的方案数。有转移:\[f_i=\begin{cases}\sum\limits_{j=0}^{i-1}[i\bmod2\nej\bmod2]f_j&i\notinA\\0&i\inA\end{cases}\]考虑前......
  • AtCoder Beginner Contest 289(E,F)
    AtCoderBeginnerContest289(E,F)E(dijkstra)E这个题的大意就是有两个人,一个人在点\(1\),一个人在点\(n\),现在两个人要同时走(题目给出了点和边,还有每一个点的颜色),但是他们的下一步要到的点需要是颜色不同的,问\(1\)点出发的和\(n\)点出发的同时达到对方的起点的最短路径时哪......
  • AtCoder Beginner Contest 303
    A-SimilarString(abc303a)题目大意给定两个字符串,问这两个字符串是否相似。两个字符串相似,需要每个字母,要么完全相同,要么一个是1一个是l,要么一个是0一个是o解题思路按照题意模拟即可。可以将全部1换成l,全部0换成o,再判断相等。神奇的代码#include<bits/stdc++.h>us......
  • AtCoder Regular Contest 153 D Sum of Sum of Digits
    洛谷传送门AtCoder传送门又浪费一道好题我首先想的是,\(x\)显然最优取某些\(a_i\)往前进位时的值。然后就误以为\(x\)的取值是\(O(n\log_{10}V)\)的了……既然没发现什么性质,那就直接dp吧!设\(f_{d,i}\)为从低到高前\(d\)位,所有\(a_i\)进位之和为\(i\)。然......
  • ROS2-Beginner:CLI tools-1、环境配置
    1、环境配置目标:本教程告诉读者怎样准备ROS2环境背景:ROS2依赖于使用shell环境组合工作空间的概念,“工作区”是一个ROS术语,表示您使用ROS2进行开发的系统上的位置。ROS2的核心工作空间称为底层(underlay)。后续的局部工作空间称为覆盖(overlays)。当使用ROS2进行开发时,通常会同......
  • AtCoder Regular Contest 161
    PrefaceARC战俘闪总出列这场一上来就感觉状态不太对,先是A顺序敲反WA了一发,然后C题看到秒出一个贪心然后也WA了看一眼榜发现D过的比C多,然后跑去把D写了,中间还偷偷挂了两发最后50min回去沉淀C题,结果换了两种写法都还是一样的挂,后面发现想法还是有纰漏总结:彩笔A-MakeM考虑......
  • AtCoder Regular Contest 148 E ≥ K
    洛谷传送门AtCoder传送门是一道不错的计数。考察合法序列的形态,容易发现:不能出现两个\(<\frac{k}{2}\)的数相邻;如果\(x<\frac{k}{2},y\ge\frac{k}{2}\),那么\(|y-\frac{k}{2}|\ge|x-\frac{k}{2}|\)。考虑不直接排列,而是按照一定的顺序插入。考虑按照\(|x......
  • AtCoder Beginner Contest 290(D,E)
    AtCoderBeginnerContest290(D,E)D(思维,数学)D这个题的大意就是我们需要标记\(n\)个位置,他是这样标记的,一开始有一个初始值为\(0\)的\(x\),第一个标记的是\(0\)位置,然后下一步,我们把\(x\)变成\((x+d)modn\),如果这个位置没有被标记,否则把\(x\)变成\((x+1)modn\),这个是没有......
  • AtCoder Regular Contest 161 E Not Dyed by Majority (Cubic Graph)
    洛谷传送门AtCoder传送门给构造题提供了一种新的思路。如果答案占总方案数的比较大,可以考虑随机化。例如本题,考虑随机化,难点变成判断一个方案是否可行。考虑2-SAT,如果一个点是\(\text{B}\),那么对于这个点的边,有一条边的另一个端点是\(\text{W}\),那么其他两个都是\(\text{......