CF Educational Codeforces Round 57划水记

因为是unrated于是就叫划水记了,而且本场也就用了1h左右。

A、B:划水去了,没做

C:大水题,根据初三课本中圆的知识,可以把角度化成弧长,而这是正多边形,所以又可以化成边数,于是假设读入为a,就是周长的a/180,gcd一下就行了,注意如果a/b这个分数满足a+1=b,那么就要ans*=2

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        int n,t,fm,fz;
        scanf("%d",&n);
        if(n==90){puts("4");continue;}
        t=__gcd(n,180);
        fm=180/t,fz=n/t;
        if(fz+1==fm)fm*=2;
        printf("%d\n",fm);
    }
}

Code C

D:首先不是h、a、r、d的字符可以删去,不用管它,而我们可以做个dp,f[i][0/1/2/3/4]表示当前位置匹配了前0/1/2/3/4个以后的最小代价

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+7;
int n,m,v[N],a[N],C[N];
ll f[N][5],ans;
char s[N];
int main()
{
    scanf("%d",&n);
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    C[‘h‘]=1,C[‘a‘]=2,C[‘r‘]=3,C[‘d‘]=4;
    for(int i=1;i<=n;i++)
    if(C[s[i]])v[++m]=C[s[i]],a[m]=a[i];
    for(int i=1;i<=m;i++)for(int j=0;j<5;j++)f[i][j]=1e18;
    for(int i=1;i<=m;i++)
    for(int j=0;j<5;j++)
    {
        if(j==v[i]-1)f[i][j]=min(f[i][j],f[i-1][j]+a[i]);
        else f[i][j]=min(f[i][j],f[i-1][j]);
        if(j==v[i])f[i][j]=min(f[i][j],f[i-1][j-1]);
    }
    ans=1e18;
    for(int j=0;j<4;j++)ans=min(ans,f[m][j]);
    printf("%lld",ans);
}

Code D

E:本场切的人数最少的题,现场当然没有想到怎么做。由于是期望,肯定是求合法方案数/总方案数,总方案数好求就是一个组合数,考虑求合法方案数。由于总分、人数范围都比较小,考虑枚举Hasan的得分,然后进行计算即可。计算过程大概就是个容斥的过程。复杂度O(玄学),总之范围小能通过就行了。

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
int p,s,r,sum,c[5222][107];
int qpow(int a,int b)
{
    int ret=1;
    while(b)
    {
        if(b&1)ret=1ll*ret*a%mod;
        a=1ll*a*a%mod,b>>=1;
    }
    return ret;
}
int calc(int n,int m,int x)
{
    int ret=0;
    for(int i=0;i<=m&&x*i<=n;i++)
    {
        int add=1ll*c[m][i]*c[n-x*i+m-1][m-1]%mod;
        if(i&1)ret=(ret-add+mod)%mod;
        else ret=(ret+add)%mod;
    }
    return ret;
}
int main()
{
    scanf("%d%d%d",&p,&s,&r);
    if(p==1){puts("1");return 0;}
    for(int i=0;i<=5200;i++)
    {
        c[i][0]=1;
        for(int j=1;j<=i&&j<=100;j++)c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
    }
    for(int x=r;x<=s;x++)
    if(x*p>=s)
    for(int i=1;i<=p;i++)
    if(i*x<=s&&(p-i)*(x-1)+x*i>=s)
    {
        if(i==p)sum=(sum+(x*i==s?qpow(i,mod-2):0))%mod;
        sum=(sum+1ll*c[p-1][i-1]*calc(s-x*i,p-i,x)%mod*qpow(i,mod-2))%mod;
    }
    sum=1ll*sum*qpow(c[s-r+p-1][p-1],mod-2)%mod;
    printf("%d",sum);
}

Code E

F:又是一道期望题,其实还是不太难,可以把答案分成三类:1、两者都在原有序列。2、两者都在-1上。3、一个在-1上一个在原有序列。第一类可以用归并排序求解逆序对,第二类直接记录状态f[i]=f[i-1]+(i-1)/2,考虑插入最大的即可。第三类也很好求,记录每个位置前面有多少空当,比当前数小的有几个数没有出现,这个都可以前缀和O(1)求得,然后枚举每个不为-1的位置,答案分成两部分:1、前面的空当数/总空当数*比该数大的没填的个数。2、后面的空当数/总空当数*比该数小的没填的个数。为什么呢?每个数分到前/后的机会是均等的,考虑随机性即可,不能把问题想复杂。复杂度O(nlogn),瓶颈在于归并排序

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7,mod=998244353;
int n,m,ans,p[N],a[N],b[N],c[N],sp[N],sv[N],inv[N],f[N];
void merge(int l,int r)
{
    if(l>=r)return;
    int m=(l+r)/2,i,j,n1=m-l+1,n2=r-m;
    merge(l,m);merge(m+1,r);
    for(i=1;i<=n1;i++)b[i]=a[l+i-1];
    for(i=1;i<=n2;i++)c[i]=a[m+i];
    i=j=1;b[n1+1]=c[n2+1]=1e9;
    for(int k=l;k<=r;k++)
    if(b[i]<=c[j])a[k]=b[i++];
    else a[k]=c[j++],ans=(ans+n1-i+1)%mod;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)sv[i]=1;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&p[i]);
        sp[i]=sp[i-1];
        if(p[i]>0)a[++m]=p[i],sv[p[i]]=0;
        else sp[i]++;
    }
    for(int i=1;i<=n;i++)sv[i]+=sv[i-1];
    inv[0]=inv[1]=1;
    for(int i=2;i<=n;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    for(int i=2;i<=n;i++)f[i]=(f[i-1]+1ll*(i-1)*inv[2])%mod;
    merge(1,m);
    ans=(ans+f[n-m])%mod;
    for(int i=1;i<=n;i++)
    if(p[i]>0)
    {
        int P=1ll*(sv[n]-sv[p[i]])*sp[i-1]%mod*inv[sp[n]]%mod;
        ans=(ans+P)%mod;
        P=1ll*sv[p[i]-1]*(sp[n]-sp[i])%mod*inv[sp[n]]%mod;
        ans=(ans+P)%mod;
    }
    printf("%d",ans);
}

Code F

G:弱智题没写出来,第二天早上一看就会,是不是晚上智商有debuff水平低啊。题解:没什么好讲的,每次只有+指定是数才可以,n次可以NTT转移(我都想到了NTT还不会)没写出来的原因:想复杂问题,每次还倍增,硬生生的把复杂度从O(9nlogn)->O(9nlog2n),其实NTT(a,1)后,对a数组直接乘n次方再NTT(a,-1)就行了

#include<bits/stdc++.h>
using namespace std;
const int N=2098000,p=998244353;
int n,k,a[N],R[N],ans;
int qpow(int a,int b)
{
    int ret=1;
    while(b)
    {
        if(b&1)ret=1ll*ret*a%p;
        a=1ll*a*a%p,b>>=1;
    }
    return ret;
}
void NTT(int*a,int n,int typ)
{
    for(int i=1;i<n;i++)
    {
        R[i]=(R[i>>1]>>1)|((i&1)*(n>>1));
        if(i<R[i])swap(a[i],a[R[i]]);
    }
    for(int i=1;i<n;i<<=1)
    {
        int wn=qpow(3,typ*(p/(i*2))+p-1);
        for(int j=0;j<n;j+=i*2)
        for(int k=0,w=1;k<i;k++,w=1ll*w*wn%p)
        {
            int x=a[j+k],y=1ll*w*a[j+k+i]%p;
            a[j+k]=(x+y)%p;
            a[j+k+i]=(x-y+p)%p;
        }
    }
    if(typ==1)return;
    int invn=qpow(n,p-2);
    for(int i=0;i<n;i++)a[i]=1ll*a[i]*invn%p;
}
int main()
{
    scanf("%d%d",&n,&k);
    n/=2;
    for(int i=1,x;i<=k;i++)scanf("%d",&x),a[x]=1;
    int nn=1;
    while(nn<=n*18)nn<<=1;
    NTT(a,nn,1);
    for(int i=0;i<nn;i++)a[i]=qpow(a[i],n);
    NTT(a,nn,-1);
    for(int i=0;i<=n*9;i++)ans=(ans+1ll*a[i]*a[i])%p;
    printf("%d",ans);
}

Code G

原文地址:https://www.cnblogs.com/hfctf0210/p/10198258.html

时间: 2024-11-08 22:45:39

CF Educational Codeforces Round 57划水记的相关文章

Educational Codeforces Round 57 (Rated for Div. 2)

get人生第二场CF! 成绩:(exACM) rank858 AC3/7 Penalty57 rating1648(+52) 题目:Educational Codeforces Round 57 (Rated for Div. 2) 错题题解: D. Easy Problem E. The Top Scorer F. Inversion Expectation G. Lucky Tickets 原文地址:https://www.cnblogs.com/xht37/p/10198321.html

CF Educational Codeforces Round 10 D. Nested Segments 离散化+树状数组

题目链接:http://codeforces.com/problemset/problem/652/D 大意:给若干个线段,保证线段端点不重合,问每个线段内部包含了多少个线段. 方法是对所有线段的端点值离散化,按照左端点从大到小排序,顺着这个顺序处理所有线段,那么满足在它内部的线段一定是之前已经扫到过的.用树状数组判断有多少是在右端点范围内. 1 #include <iostream> 2 #include <vector> 3 #include <algorithm>

Educational Codeforces Round 57 Solution

A. Find Divisible 签到. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int t, l, r; 5 6 int main() 7 { 8 scanf("%d", &t); 9 while (t--) 10 { 11 scanf("%d%d", &l, &r); 12 printf("%d %d\n", l, l * 2); 13

Educational Codeforces Round 57 (Rated for Div. 2) ABCDF题解

ZZ出题人写NTT写成ZZ了吧,全是998244353,不需要取模的东西强行取模搞得我以为答案很大想了好久(指B题) A.任意输出 \([l,r]\) 内的一组满足 \(x \mid y\) 的 \(x, y\) ,保证有答案 我输出了 \(\lfloor \frac{r}{l} \rfloor \times l\) 输出2l也行 int main() { int T; in, T; while (T--) { int l, r; in, l, r; out, l, ' ', r / l * l

Educational Codeforces Round 57 (Rated for Div. 2) 前三个题补题

感慨 最终就做出来一个题,第二题差一点公式想错了,又是一波掉分,不过我相信我一定能爬上去的 A Find Divisible(思维) 上来就T了,后来直接想到了题解的O(1)解法,直接输出左边界和左边界*2即可 代码 #include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); long long x,y,t; cin>>t;

Codeforces Educational Codeforces Round 57 题解

传送门 Div 2的比赛,前四题还有那么多人过,应该是SB题,就不讲了. 这场比赛一堆计数题,很舒服.(虽然我没打) E. The Top Scorer 其实这题也不难,不知道为什么这么少人过. 考虑枚举那人的分数和有多少人和他同分,推一下就会发现我们只需要知道\(calc(sum,n,top)\)表示\(sum\)分,分给\(n\)个人,分数小于\(top\),的方案数. 好像不是很好直接搞,考虑容斥,枚举一下至少有几个人不满足条件即可. #include<bits/stdc++.h> na

Educational Codeforces Round 40千名记

人生第二场codeforces.然而遇上了Education场这种东西 Educational Codeforces Round 40 下午先在家里睡了波觉,起来离开场还有10分钟. 但是突然想起来还没报名呢,并且电脑又是开机黑屏什么情况 莫非为之后的凉凉埋下了伏笔? 比赛之前联系了下余翱和叶可禾,似乎都要去切题的样子? 想到第一次有人一起打CF还是有点小激动的.于是果断屏蔽余翱QQ上的刷屏去看A题了. A. Diagonal Walking 非常仔细地把题读了一遍,然后……啥这不是字符串入门题

Educational Codeforces Round 21 G. Anthem of Berland(dp+kmp)

题目链接:Educational Codeforces Round 21 G. Anthem of Berland 题意: 给你两个字符串,第一个字符串包含问号,问号可以变成任意字符串. 问你第一个字符串最多包含多少个第二个字符串. 题解: 考虑dp[i][j],表示当前考虑到第一个串的第i位,已经匹配到第二个字符串的第j位. 这样的话复杂度为26*n*m*O(fail). fail可以用kmp进行预处理,将26个字母全部处理出来,这样复杂度就变成了26*n*m. 状态转移看代码(就是一个kmp

Educational Codeforces Round 23 F. MEX Queries(线段树)

题目链接:Educational Codeforces Round 23 F. MEX Queries 题意: 一共有n个操作. 1.  将[l,r]区间的数标记为1. 2.  将[l,r]区间的数标记为0. 3.  将[l,r]区间取反. 对每个操作,输出标记为0的最小正整数. 题解: hash后,用线段树xjb标记一下就行了. 1 #include<bits/stdc++.h> 2 #define ls l,m,rt<<1 3 #define rs m+1,r,rt<&l