codeforces Hello 2019

codeforces Hello 2019

Hello candidate master

新年第一场cf2333

感觉难度比 good bye 2018良心很多啊

T1

日常送分题,判断有没有相同的

#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int n;
char s[10],t[10]; 
int main(){
//  freopen("1.in","r",stdin);
    scanf("%s",s+1);
    for(int i=1;i<=5;i++){
        scanf("%s",t+1);
        if(s[1]==t[1]||s[2]==t[2]){
            printf("YES\n");
            return 0;
        }
    }
    printf("NO\n");
    return 0;
}

T2

日常送分题 x 2

#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=20;
int n,a[maxn];
void dfs(int x,int y){
    if(x>n){
        if(y%360==0){
            printf("YES\n");
            exit(0);
        }
        return;
    }
    dfs(x+1,y+a[x]);
    dfs(x+1,y-a[x]);
}
int main(){
//  freopen("1.in","r",stdin);
    //freopen(".out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    dfs(1,0);
    printf("NO");
    return 0;
}

T3

。。。我去怎么三道sb题

对于每个括号序列,统计它左边和右边分别需要补几个,如果都要补就没法用,否则设补左边正,补右边负,开个\(map\)存一下取最小值就好了

#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=5e5+100;
int n,b[maxn],num;
char s[maxn];
map<int,int>p;
map<int,bool>cz;
int main(){
//  freopen("1.in","r",stdin);
    //freopen(".out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        int len=strlen(s+1),l=0,r=0;
        for(int j=1;j<=len;j++)
            if(s[j]=='(') l++;
            else
                if(l) l--;
                else r++;
        if(l&&r) continue;
        int k;
        if(l) k=l;
        else k=-r;
        p[k]++;
        if(k<0&&!cz[k]) cz[k]=1,b[++num]=k;
    }
    int ans=0;
    for(int i=1;i<=num;i++)
        ans+=min(p[b[i]],p[-b[i]]);
    ans+=p[0]/2;
    printf("%d\n",ans);
    return 0;
}

T4

题意:一个数n,每次将自己等概率变为自己的一个约数,问变了K次后的n期望大小 (n<1e14 , k<1e4)

把n分解质因数,设\(n=p_1^{k_1}p_2^{k_2}...p_m^{k_m}\)

可以发现,每变一次,每个指数\(k_i\)都会等概率地变成\(0-k_i\)中的一个

那么我们对于每个质因数都求一下他的期望,然后全都乘起来应该就是最后的答案了

对于一个质因数\(p_i^{k_i}\),怎么算他的期望呢?

\(k_i\)变了\(j\)次变成\(x\)的概率为\(f[j][x]\),因为\(x\)一定是由一个大于等于\(x\)的数\(y\)\(1/(y+1)\)(有可能变成零,所以是\(y+1\))的概率变来的,所以
\[ f[j][x]=\sum_{y=x}^{k_i}{f[j-1][y]*inv[y+1]} \]
当然,\(f[0][k_i]=1\)

\(f[n][i]\)都求出来了,那么这个质因数的期望就是\(\sum_{i=1}^{k_i}{f[n][i]*pow(p,i)}\)

然后这个\(dp\)可以用前缀和优化(\(y\)按照从\(k_i\)\(x\)来枚举)时间复杂度\(O(K*k_i)\)

\(n\)的质因数个数以及每个质因数的次数\(k_i\)都是\(logn\)级别的

所以总时间复杂度\(O(Klog ^2n)\)

#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=3e7;
const ll P=1e9+7;
int p[maxn],num;
ll n,k,inv[10000],f[2][10000],b[10000],tot,c[10000]; 
bool vis[maxn];
void ycl(){
    int lim=3e7;
    for(int i=2;i<lim;i++){
        if(!vis[i])
            p[++num]=i;
        for(int j=1;1ll*p[j]*i<lim;j++){
            vis[p[j]*i]=1;
            if(i%p[j]==0) break;
        }
    }
    inv[0]=inv[1]=1;  
    for(int i=2;i<=1000;i++)
        inv[i]=(1ll*(P-P/i)*inv[P%i])%P; 
}
inline ll poww(ll x,ll y){
    ll base=1;
    while(y){
        if(y&1) base=base*x%P;
        x=x*x%P;
        y>>=1;
    }
    return base;
}
ll work(ll x,int y){
    for(int i=0;i<=y;i++) f[0][i]=0;
    int nw=0;f[0][y]=1;
    for(int i=1;i<=k;i++){
        nw^=1;
        ll siz=0;
        for(int j=y;j>=0;j--){
            siz+=f[nw^1][j]*inv[j+1]%P,siz%=P;
            f[nw][j]=siz;
        }
    }
    ll siz=0;
    for(int i=0;i<=y;i++)
        siz+=poww(x,i)*f[nw][i]%P,siz%=P;
    siz%=P; 
    return siz;
}
int main(){
//  freopen("1.in","r",stdin);
    //freopen(".out","w",stdout);
    ycl();
    scanf("%I64d%I64d",&n,&k);
    for(int i=1;i<=num&&p[i]<=n;i++)
        if(n%p[i]==0){
            b[++tot]=p[i];
            while(n%p[i]==0) n/=p[i],c[tot]++;
        }
    ll ans=1;
    for(int i=1;i<=tot;i++)
        ans=ans*work(b[i],c[i])%P;
    if(n!=1) ans=ans*work(n,1)%P;
    printf("%I64d\n",(ans%P+P)%P);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/nianheng/p/10223220.html