Codeforces Round #538 (Div. 2)

目录

  • Codeforces 1114

    • A.Got Any Grapes?
    • B.Yet Another Array Partitioning Task
    • C.Trailing Loves (or L‘oeufs?)
    • D.Flood Fill(区间DP)
    • E.Arithmetic Progression(交互 二分 随机化)
    • F.Please, another Queries on Array?(线段树 欧拉函数)

Codeforces 1114

比赛链接

貌似最近平均难度最低的一场div2了...
但我没有把握住机会TAT
D题没往DP想 写模拟自闭了40多分钟...才发现是个傻逼区间DP
再多二十分钟就能调出F的傻逼错误了...

A.Got Any Grapes?

puts的返回值原来是0。。刚开始写的return !puts("NO");在样例上RE了一次= =

#include <set>
#include <map>
#include <cstdio>
#include <cctype>
#include <vector>
#include <cstring>
#include <algorithm>
#define pc putchar
#define gc() getchar()
typedef long long LL;

inline int read()
{
    int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    for(;isdigit(c);now=now*10+c-48,c=gc());
    return now*f;
}

int main()
{
    int x=read(),y=read(),z=read(),a=read(),b=read(),c=read();
    if(a<x) return puts("NO"),0;
    a-=x;
    if(a+b<y) return puts("NO"),0;
    int tot=a+b+c-y-z;
    if(tot<0) return puts("NO"),0;
    return puts("YES"),0;

    return 0;
}

B.Yet Another Array Partitioning Task

因为可以每隔\(m\)个分一段,所以选出最大的\(m*k\)个数,每隔\(m\)个分一段就行了。

#include <set>
#include <map>
#include <cstdio>
#include <cctype>
#include <vector>
#include <cstring>
#include <algorithm>
#define pc putchar
#define gc() getchar()
typedef long long LL;
const int N=2e5+5;

struct Node
{
    int v,p;
    bool operator <(const Node &x)const
    {
        return v==x.v?p<x.p:v>x.v;
    }
}A[N];

inline int read()
{
    int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    for(;isdigit(c);now=now*10+c-48,c=gc());
    return now*f;
}

int main()
{
    static int Ans[N];
    static bool vis[N];
    int n=read(),m=read(),K=read();
    for(int i=1; i<=n; ++i) A[i]=(Node){read(),i};
    std::sort(A+1,A+1+n);
    LL sum=0;
    for(int i=1; i<=K*m; ++i) vis[A[i].p]=1, sum+=A[i].v;
    int cnt=0;
    for(int i=1,t=0; i<=n; ++i)
        if(vis[i] && ++t==m)
            t=0, Ans[++cnt]=i;
    printf("%I64d\n",sum);
    for(int i=1; i<cnt; ++i) printf("%d ",Ans[i]);

    return 0;
}

C.Trailing Loves (or L‘oeufs?)

\(Description\)
给定\(n,b\),求\(b\)进制下\(n!\)的末尾零的个数。
\(n\leq10^{18},\ b\leq10^{12}\)。

\(Solution\)
经典问题。。所以也是一道能搜到的题。。
如果\(d=10\),就是求\(n!\)有多少个\(2\)和\(5\)的因子\(c_2,c_5\),答案是\(\min\{c_2,c_5\}\),不难理解。
如果\(d\neq10\),同样对\(d\)质因数分解,令\(d=\prod_{i=1}^kp_i^{a_i},\ a_i\neq0\),依次求出\(n!\)中有多少个\(p_i\),记为\(c_i\),答案就是\(\min_{i=1}^k\{c_i\}\)。
求\(n!\)中质因子\(p\)的个数的公式:\[f(n)=\left\lfloor\frac{n}{p}\right\rfloor +\left\lfloor\frac{n}{p^2}\right\rfloor +\left\lfloor\frac{n}{p^3}\right\rfloor +\cdots\]

实际写的时候\(n\)每次除以\(p\)即可,不需要分母不断乘\(p\),会爆long long。。。

#include <set>
#include <map>
#include <cstdio>
#include <cctype>
#include <vector>
#include <cstring>
#include <algorithm>
#define pc putchar
#define gc() getchar()
typedef long long LL;
const int N=1e6+5;

inline LL read()
{
    LL now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-48,c=gc());
    return now;
}
LL Calc(LL x,LL y)
{
    LL res=0;
    for(; x; x/=y) res+=x/y;
    return res;
}

int main()
{
    static LL P[N];
    static int tm[N];
    LL n=read(),b=read();
//1
    LL ans=1ll<<60;
    for(int i=2; 1ll*i*i<=b; ++i)
        if(!(b%i))
        {
            LL cnt=1; b/=i;
            while(!(b%i)) b/=i, ++cnt;
            ans=std::min(ans,Calc(n,i)/cnt);
        }
    if(b!=1) ans=std::min(ans,Calc(n,b));
    printf("%I64d\n",ans);
    return 0;
//2
    int t=0;
    for(int i=2; 1ll*i*i<=b; ++i)
        if(!(b%i))
        {
            P[++t]=i, b/=i, tm[t]=1;
            while(!(b%i)) b/=i, ++tm[t];
        }
    if(b!=1) P[++t]=b, tm[t]=1;
    ans=1ll<<60;
    for(int i=1; i<=t; ++i)
    {
        LL cnt=0;
//      for(LL x=P[i]; x<=n&&x>0; x*=P[i]) cnt+=n/x;//这么写可能直接爆longlong爆成正数啊。。。= =
        for(LL x=n; x; x/=P[i]) cnt+=x/P[i];
        ans=std::min(ans,cnt/tm[i]);
    }
    printf("%I64d\n",ans);

    return 0;
}

D.Flood Fill(区间DP)

刚开始一看\(O(n^2)\),就想枚举起点然后模拟。。(mdzz)

无脑区间DP。。
\(f[i][j][0/1]\)表示合并完\(i\sim j\)区间,现在颜色是\(c_i/c_j\)的最小花费。转移特判一下即可。
或者先去掉相邻的重复元素,直接\(f[i][j]\)表示合并完\(i\sim j\)区间的最小花费。如果\(c_i=c_j\),\(f[i][j]=f[i+1][j-1]+1\);否则\(f[i][j]=\min(f[i+1][j],\ f[i][j-1])+1\)。

#include <set>
#include <map>
#include <cstdio>
#include <cctype>
#include <vector>
#include <cstring>
#include <algorithm>
#define pc putchar
#define gc() getchar()
typedef long long LL;
const int N=5005;

int A[N],f[N][N][2];

inline int read()
{
    int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    for(;isdigit(c);now=now*10+c-48,c=gc());
    return now*f;
}
bool Check(int n)
{
    for(int i=1; i<=n; ++i) if(A[i]!=A[1]) return 0;
    puts("0");
    return 1;
}

int main()
{
    int n=read();
    for(int i=1; i<=n; ++i) A[i]=read();
    if(Check(n)) return 0;
    memset(f,0x3f,sizeof f);
    for(int i=1; i<=n; ++i) f[i][i][0]=f[i][i][1]=0;
    for(int l=1; l<n; ++l)
        for(int i=1; i+l<=n; ++i)
        {
            int j=i+l;
            f[i][j][0]=std::min(f[i][j-1][0]+2-2*(A[i]==A[j]),std::min(f[i][j-1][1]+2-(A[j-1]==A[j])-(A[i]==A[j]),std::min(f[i+1][j][0]+1-(A[i]==A[i+1]),f[i+1][j][1]+1-(A[j]==A[i]))));
            f[i][j][1]=std::min(f[i][j-1][0]+1-(A[i]==A[j]),std::min(f[i][j-1][1]+1-(A[j-1]==A[j]),std::min(f[i+1][j][0]+2-(A[i]==A[i+1])-(A[i]==A[j]),f[i+1][j][1]+2-2*(A[j]==A[i]))));
        }
    printf("%d\n",std::min(f[1][n][0],f[1][n][1]));

    return 0;
}

E.Arithmetic Progression(交互 二分 随机化)

首先通过操作二可以二分出最大值。
然后剩下\(30\)次操作一能干什么呢。。只能帮我们确定出数列中有某些数,那能做的好像就是随机确定\(30\)个数。
等差数列中任意两个数作差可以得到\(x\cdot d\),把确定出的数两两作差然后对差求\(\gcd\),是有可能得到真正的\(d\)的。
正确概率是多少呢,感觉挺高的。。然后有最大值有公差,就做完了。
官方题解中对正确概率有证明,大约是\(1.86185\times10^{-9}\)。

做差的时候先排序,只求出相邻两个数的差就够了,并不需要所有数两两之间作差。

#include <ctime>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define Flush() fflush(stdout)
typedef long long LL;
const int N=1e6+5;

int id[N];

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-48,c=gc());
    return now;
}
inline int Rd()
{
    return rand()<<15|rand();
}
inline int Query1(int n)
{
    int p=Rd()%n+1;
    printf("? %d\n",id[p]), Flush();
    std::swap(id[p],id[n]);//不这么写也行 差别不大 无所谓啦
    return read();
}
inline int Query2(int x)
{
    printf("> %d\n",x), Flush();
    return read();
}

int main()
{
    static int A[66];
    srand(time(0));
    int n=read();
    int l=0,r=1e9,mid,mx=0,rest=60;
    while(l<=r)
        if(--rest,Query2(mid=l+r>>1)) mx=l=mid+1;
        else r=mid-1;

    for(int i=1; i<=n; ++i) id[i]=i;
    int t=0; rest=std::min(rest,n);
    for(int now=n; rest; --rest) A[++t]=Query1(now--);

    std::sort(A+1,A+1+t), A[++t]=mx;
    int d=A[2]-A[1];
    for(int i=3; i<=t; ++i) if(A[i]!=A[i-1]) d=std::__gcd(d,A[i]-A[i-1]);
    printf("! %d %d\n",mx-(n-1)*d,d), Flush();

    return 0;
}

F.Please, another Queries on Array?(线段树 欧拉函数)

原文地址:https://www.cnblogs.com/SovietPower/p/10361309.html

时间: 2024-08-29 21:14:55

Codeforces Round #538 (Div. 2)的相关文章

Codeforces Round #538 (Div. 2) (CF1114)

Codeforces Round #538 (Div. 2) (CF1114) ??今天昨天晚上的cf打的非常惨(仅代表淮中最低水平 ??先是一路缓慢地才A掉B,C,然后就开始杠D.于是写出了一个O(n^2)的线性dp,然后就wa6,调到结束.结束后发现完全看漏了两句话.噢,起始点!!! ??好吧然后算算自己有可能这一场要变成+0,反正在0左右. 结束后开始然后开始写D,顺便思考F.结果写完D发现A怎么fst了,然后...因为习惯于对相似的语句复制粘贴,有些东西没有改--三句话都在 -a!!!(

Codeforces Round #538 (Div. 2) D. Flood Fill 【区间dp || LPS (最长回文序列)】

任意门:http://codeforces.com/contest/1114/problem/D D. Flood Fill time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output You are given a line of nn colored squares in a row, numbered from 11 to nn f

Codeforces Round #538 (Div. 2) E 随机数生成

https://codeforces.com/contest/1114/problem/E 题意 交互题,需要去猜一个乱序的等差数列的首项和公差,你能问两种问题 1. 数列中有没有数比x大 2. 数列的第i项是什么 最多只能问60次 题解 首先用第一种问题+二分问出数列最大的数是多少,最多二十次 然后用第二种问题尽可能分散的询问第i项,然后将问出的数组排序,对相邻两个数的差求gcd 随机数生成链接 https://codeforces.com/blog/entry/61587 https://c

[codeforces]Round #538 (Div. 2) F. Please, another Queries on Array?

题解:    $$  ans=F\left ( \prod _{i=l}^{r}a_i \right ) $$ $$ =(p_i-1){p_i}^{k_i-1}*.....*(p_j-1){p_j}^{k_j-1} $$ $$={p_i}^{k_i}*.....*{p_j}^{k_j}*(\frac{p_i-1}{p_i}*......*\frac{p_j-1}{p_j})  $$ 因为数据范围保证$ a_i\leq 300 $ 所以在这个范围内只有62个素因子  我们可以直接每一位对应一bit

[比赛] Codeforces Round #538 (Div. 2) solution (贪心,数学其他,二分,线段树)

已经写了100篇题解啦! link solution pdf #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; inline int read(){ int f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c

Codeforces Round #428 (Div. 2)

Codeforces Round #428 (Div. 2) A    看懂题目意思就知道做了 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i

Codeforces Round #424 (Div. 2) D. Office Keys(dp)

题目链接:Codeforces Round #424 (Div. 2) D. Office Keys 题意: 在一条轴上有n个人,和m个钥匙,门在s位置. 现在每个人走单位距离需要单位时间. 每个钥匙只能被一个人拿. 求全部的人拿到钥匙并且走到门的最短时间. 题解: 显然没有交叉的情况,因为如果交叉的话可能不是最优解. 然后考虑dp[i][j]表示第i个人拿了第j把钥匙,然后 dp[i][j]=max(val(i,j),min(dp[i-1][i-1~j]))   val(i,j)表示第i个人拿

Codeforces Round #424 (Div. 2) C. Jury Marks(乱搞)

题目链接:Codeforces Round #424 (Div. 2) C. Jury Marks 题意: 给你一个有n个数序列,现在让你确定一个x,使得x通过挨着加这个序列的每一个数能出现所有给出的k个数. 问合法的x有多少个.题目保证这k个数完全不同. 题解: 显然,要将这n个数求一下前缀和,并且排一下序,这样,能出现的数就可以表示为x+a,x+b,x+c了. 这里 x+a,x+b,x+c是递增的.这里我把这个序列叫做A序列 然后对于给出的k个数,我们也排一下序,这里我把它叫做B序列,如果我

[Codeforces] Round #352 (Div. 2)

人生不止眼前的狗血,还有远方的狗带 A题B题一如既往的丝帛题 A题题意:询问按照12345678910111213...的顺序排列下去第n(n<=10^3)个数是多少 题解:打表,输出 1 #include<bits/stdc++.h> 2 using namespace std; 3 int dig[10],A[1005]; 4 int main(){ 5 int aa=0; 6 for(int i=1;;i++){ 7 int x=i,dd=0; 8 while(x)dig[++dd