1. 程式人生 > >CF Educational Codeforces Round 57劃水記

CF Educational Codeforces Round 57劃水記

== 部分 ret 期望 直接 cat sin 歸並排序 怎麽

因為是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

CF Educational Codeforces Round 57劃水記