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

AtCoder Beginner Contest 300(E,F)

时间:2023-05-25 22:11:52浏览次数:50  
标签:AtCoder frac Beginner 300 long int include dp define

AtCoder Beginner Contest 300(E,F)

E (概率dp)

E

这个题意大致就是一开始有一个初始数\(x\)为\(1\),然后我们有一个骰子,最后得到的点数概率一样,为\(\frac{1}{6}\),如果这一次得到的点数为\(i\),那么\(x\)会变成\(i\times x\),问最后得到数\(n\)的概率为多少

先感性的分析一波,对于这六个数,除了\(1\)之外都可以改变\(x\),那么我们可以不用考虑\(1\)得到的效果,毕竟不管得没得到\(1\)效果都是一样的,那么我们每一次投中的概率就是\(\frac{1}{5}\)

下面我给出证明

假设\(dp[i]\)是得到的数为\(i\)的概率,那么我们可以得到

\[dp[i]=\frac{1}{6}dp[i]+\sum_{j=1}^n\frac{1}{6}dp[\frac{i}{j}] \]

我把\(1\)和后面的数分开了

然后可以移项,把\(dp[i]\)放在一边,毕竟这个才是我们需要的

\[\frac{5}{6}dp[i]=\sum_{j=1}^n\frac{1}{6}dp[\frac{i}{j}] \]

然后把\(dp[i]\)的系数变成\(1\),这样好看一点

\[dp[i]=\sum_{j=1}^n\frac{1}{5}dp[\frac{i}{j}] \]

这样,对于后面的非\(1\)数,得到的概率可以看成\(\frac{1}{5}\)了

然后我看到一个很好的解法,很易懂,大佬博客

他是从\(1\)逐渐往后面找,每得到一个新的点,都会乘上这个概率,(然后还用上了记忆化)

只有找到了\(n\)才是正确的

幸好这些数都就算是最小的\(2\)最多也只有\(64\)多次,而且,每次找都不会往回找,而是一直找,而且不会进入死循环,但是这个想法真的好好,有点像\(dfs\)在不断的往前找,走了一步就加一的感觉,我自己最初的想法是把那个\(n\)分解成若干个\(2,3,5\),但是这个也不太好些,因为还有\(4,6\)的情况,还不止,还要考虑顺序,感觉有点复杂

#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=1e6+10;
const int mod=998244353;
int p;
int n;
unordered_map<int,int>f;
int ksm(int x,int p)
{
    int res=1;
    while (p)
    {
        if(p&1) res=res*x%mod;
        x=x*x%mod;
        p>>=1;
    }
    return res%mod;
}
int inv(int x)
{
    return ksm(x,mod-2);
}
int getf(int x)
{
    if(x>n) return 0;
    if(x==n) return 1;
    if(f.count(x))return f[x];
    int res=0;
    for (int i=2;i<=6;i++)
    {
        res=(res+getf(i*x))%mod;
    }
    res=res*p%mod;
    f[x]=res;
    return f[x];
}
signed main ()
{
    cin>>n;
    p=inv(5);
    int ans=getf(1);
    cout<<ans<<"\n";
    system ("pause");
    return 0;
}

F (二分)

F

这个题的大意是给你一个长度为\(n\)的只由\(x,o\)两个字符组成的字符串\(s\),我们可以得到一个\(T\)字符串,\(T=m\times s\),我们可以从这个\(T\)里面,选出\(k\)个\(x\)变成\(o\),问最后我们可以得到最大的连续\(o\)的长度,而且,这道题还提醒了我们\(T\)里面的\(x\)的数量一定是够的(所以不存在没有足够\(k\))

这个呢

我们可以先从第一个\(s\)看,对于\(l,r\)这一段,要把这一段都变成\(o\)的代价就是这一段里面\(x\)的数量,所以,我们可以预先把\(x\)的前缀数量记录下来

对于一个最长的\(o\)串,一定是有最左端点一定在第一个字符串上面,(这是最优的,后面的和它都是一样的,而且越前面越代表答案可能越大)

我们枚举最左端点

然后对于第一个字符串,找到一个有最右端点\(sum[r]-sum[l]\)小于等于\(k\),那么此时我们就已经获得了\(r-l+1\)的\(o\)了,如果我们要继续往后找第二个字符串的话,只有\(r\)等于\(n\)时才可以(不然不就是连最后一个都到不了,根本不需要考虑后面的)

对于往后找,我们先看了剩余的操作次数可不可以把字符串全部都变成\(o\),这样把可以全部变成\(o\)的考虑

如果还有剩余,我们就去考虑,剩下的最远可以到哪一个位置

我之前一直在担心会不会操作不够,其实完全不用担心,如果我们对于这一次的最左端需要的操作数还不够,我们可以用到那些和这些没有关系的\(x\)上(毕竟题目已经告诉你了\(x\)的数量一定大于等于\(k\),我之前就是考虑到这儿,每次都判断一下是不是等于\(k\),结果\(wa\)了

#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=3e5+10;
const int mod=998244353;
int m,k,n;
string s;
int sum[maxn];
int find(int x,int last,int l,int r)
{
    int ans=-1;
    while (l<=r)
    {
        int mid=(l+r)>>1;
        int now=sum[mid]-last;
        if(now<=x)
        {
            ans=mid;
            l=mid+1;
        }
        else r=mid-1;
    }
    return ans;
}
signed main ()
{
    cin>>n>>m>>k;
    cin>>s;
    s=" "+s;
    for (int i=1;i<=n;i++)
    {
        int val=0;
        if(s[i]=='x') val=1;
        sum[i]=sum[i-1]+val;
    }
    int ans=0;
    for (int i=1;i<=n;i++)
    {
        int l=find(k,sum[i-1],i,n);
        if(l==-1) continue;
        int val=(l-i+1);
        int cnt=sum[l]-sum[i-1];
        if(l<n)
        {
            ans=max(ans,val);
        }
        else if(l==n)
        {
            int cha=(k-cnt)/sum[n];
            val+=min(cha,m-1ll)*n;
            if(cha<m-1ll)
            {
                int res=(k-cnt)-cha*sum[n];
                int pp=find(res,0,1,n);
                if(pp!=-1)
                {
                    val+=pp;
                }
            }
            ans=max(ans,val);
        }
    }
    cout<<ans<<"\n";
    system ("pause");
    return 0;
}

标签:AtCoder,frac,Beginner,300,long,int,include,dp,define
From: https://www.cnblogs.com/righting/p/17433126.html

相关文章

  • AtCoder Regular Contest 146 D >=<
    洛谷传送门AtCoder传送门考虑直接增量构造。把条件拆成形如\(a_u\gex\)时\(a_v\gets\max(a_v,y)\),连边,跑类似一个spfa的东西,就行了。这样一定能构造出一组和最小的解。code//Problem:D->=<//Contest:AtCoder-AtCoderRegularContest146//URL:http......
  • AtCoder Beginner Contest 193 F Zebraness
    洛谷传送门AtCoder传送门复习一下最小割。考虑翻转横纵坐标和为奇数的颜色,那么就变成了,相邻两个格子,相同颜色产生\(1\)的贡献。一眼P4313文理分科。每个格子被分到\(S\)表示染黑,分到\(T\)表示染白。对于每两个相邻格子,建两个虚点,分别表示它们都染黑或者都染白的情况......
  • AtCoder Beginner Contest 302 H. Ball Collector 题解
    AtCoderBeginnerContest302H.BallCollector题意跳过。可以视作将\(a_i,b_i\)之间连了一条边,然后\(a_i,b_i\)之间只能选一个等价于对于一条边只能选择其一个端点。那么对于只包含树的联通块而言,如果都选择儿子节点,那么会有一个根节点无法被选择上;而对于包含至少一个......
  • AtCoder Beginner Contest 302(E,F,G)
    AtCoderBeginnerContest302(E,F,G)E(图,set)E这个题意大致为一开始给出\(n\)个点,没有一条边,后面陆续会有\(q\)次操作,以下两种方式\(1\),输入两个点,代表连接这两个点\(2\),输入一个点,意在把所有和这个点相连的边都删除每一次操作后我的都需要知道操作后还有多少个孤立无援的点(没......
  • AtCoder Regular Contest 132 E Paw
    洛谷传送门AtCoder传送门感觉挺educational的。观察最终形态,发现根据洞分段,有且只有一段没被覆盖,并且左端是向左的脚印,右端是向右的脚印。最终状态就这几种了,直接枚举,概率乘贡献即可。发现左端和右端不影响到对方是对称的,直接求出一边的概率。设\(f_i\)为\(i\)个洞,填......
  • AtCoder Regular Contest 132 F Takahashi The Strongest
    洛谷传送门AtCoder传送门没见过这种在新运算下做卷积的题,感觉挺新奇的。考虑Takahashi成为绝对赢家的必要条件,发现前提是Aoki和Snuke出的要相同。不妨将每种策略映射到一个四进制数(\(P\to1,R\to2,S\to3\)),定义运算\(x\otimesy=\begin{cases}x&x=y\\0......
  • AtCoder Beginner Contest 296
    AtCoderBeginnerContest296D题意给出n和m,问\(1\leqi,j\leqn\),使得\(ij\geqm\),求出这个乘积的最小值思路这两个乘数至少有一个在\([1,\sqrt{m}]\),枚举代码voidsolve(){ cin>>n>>m; intx=sqrt(m); if(n>=m){cout<<m<<endl;return;} if(x*x==m)......
  • AtCoder Regular Contest 139 C One Three Nine
    洛谷传送门AtCoder传送门闲话:做这场的B用时跟C差不多不会直接构造,因此这是一个无脑做法。考虑对于\(\forallx\in[1,n],y\in[1,m],(x+3y,3x+y)\)看成一个点,那么选择的\((x,y)\)要满足,不存在一行或一列有超过\(1\)个点。这启发我们对于合法的点\((a......
  • Atcoder 选做
    [ARC103F]DistanceSums(构造,重心)首先显然\(D_i\)的最小值被重心取到,不妨以重心为根。对于一条边连接的两个点\(x,y\),不妨设这条边\(x\)侧的点数为\(siz_x\),\(y\)侧为\(siz_y\)。那么\(D_y=D_x+siz_x-siz_y=D_x+siz_x-(n-siz_x)=D_x+2\timessiz_x-n\)。那么......
  • Atcoder Grand Contest 060 D - Same Descent Set
    先推式子。设\(f(S)\)表示decent集合恰好为\(S\)的排列个数,\(g(S)\)表示\(S\)是\(p\)的decent集合的一个子集的排列\(p\)个数,\(g'(\{a_1,a_2,\cdots,a_k\})=\dfrac{n!}{a_1!(a_2-a_1)!(a_3-a_2)!\cdots(a_k-a_{k-1})!(n-a_k)!}\),那么有:\[\begin{aligned}ans=&\......