• CodeCraft-19 and Codeforces Round #537 (Div. 2)


    A. Superhero Transformation

    水题,注意两个字符串可能长度不相等。

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll; 
    const int maxn=100010;
    map<char ,int >m;
    int main(){
        m['a']=m['e']=m['i']=m['o']=m['u']=1;
        string s1,s2;
        while(cin>>s1>>s2)
        {
            int flag=1;
            if(s1.length()!=s2.length())flag=0;
            for(int i=0;i<s1.length();i++)
            {
                if(m[s1[i]]!=m[s2[i]]){
                    flag=0;
                    break;
                }
            }
            if(flag)puts("Yes");
            else puts("No");
        }
    } 
    View Code

    B. Average Superhero Gang Power

    题意:有n个人,每个人都有权值,然后你有m次操作,每次操作可以删掉一个人或者给一个人的权值加一,使得最后剩下的人平均数最大。

    坑爹题,后台数据太水了,一开始以为只要删的剩下权值最大的那个一人,然后全加加给这个人就好了,居然过了。

    一个半小时后被hack(感谢大哥比赛中hack的我,否则要掉分了),发现比如一组样例如果全是“7 7 7 7 7”这样的就会错,因为删人不一定是最好的选择,所以就枚举删几个人,然后取最大值就好了。

    比赛刚结束我的rank1200+,rejudge后变600+,新年惨案哈哈哈。

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll; 
    const int maxn=100010;
    double a[maxn],b[maxn];
    int n,m,k;
    int main(){
        while(cin>>n>>k>>m)
        {
            for(int i=1;i<=n;i++)
            {
                scanf("%lf",&a[i]);
            }
            sort(a+1,a+1+n);
            for(int i=1;i<=n;i++)
            {
                b[i]=b[i-1]+a[i];
            }
            double ans=0;
            double tot,po;
            for(int i=0;i<=m&&i<=n-1;i++)
            {
                tot=b[n]-b[i];
                po=n-i;
                if(i<m)
                tot+=min(po*k,(double)m-i);
                ans=max(ans,tot/po);
            }
            printf("%.8f
    ",ans);
        }
    } 
    View Code

    C. Creative Snap

    题意:有2^n个格子,格子可能是空的,也可能站着许多人,有两种操作。操作一是把某一列格子平均分成两部分,操作二是把某一列格子摧毁,如果这一列格子上没有人,那么就需要耗费A的代价,如果格子上有na个人,那么就要耗费B*na*l 的代价,问把所有格子全部摧毁的最小代价是啥。

    思路:一开始完全没思路,想了很久,有人说暴力递归可以过,然后就。。试了一下?真的过了,AC后想了一下合法性。

    有一个很显然的性质,就是如果一列格子全是空的,那么必定直接付出A的代价进行摧毁,如果有人的话,就要进行考虑。但是发现最多只有k个人,也就是需要考虑的次数不会太多,所以递归并不是nlogn(n=2^30),而是klogk?

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll; 
    const int maxn=100010;
    int n,k;
    ll A,B;
    ll a[maxn];
    ll dfs(ll l,ll r){
        ll val=upper_bound(a,a+k,r)-lower_bound(a,a+k,l);
        if(val==0) return A;
        if(l==r) return val*B;
        ll mid=(l+r)>>1;
        ll left=dfs(l,mid),right=dfs(mid+1,r);
        return min(left+right,(val)*B*(r-l+1));
    }
    int main(){
        while(cin>>n>>k>>A>>B)
        {
            for(int i=0;i<k;i++)
            {
                scanf("%lld",&a[i]);
            }
            sort(a,a+k);
            ll ans=dfs(1,(ll)pow(2,n));
            printf("%lld
    ",ans);
        }
    } 
    View Code

    D. Destroy the Colony

    补。

    题意:

      给出一列大小写都有的字符串,字符串长度为偶数,每种字符代表一种人,给出q次查询,每次查询,都是讲所有人分成两部分序列,第x个字符代表的人和第y个字符代表的人要在同一个序列里面,问这样的方案数有多少。序列内排列不同则方案不同,两个序列顺序不同则方案不同。

    思路:

      设将字符串合法的分成两部分的方案数是 f 。每个字符的数量是ci,n为字符串长度,m=n/2。

      则答案应该是$frac{(m)! *  (m)!  *f *2}{  ci!   *cj !*……    }$

      我们发现这个式子里只有f是不知道的,f等于把x和y放入一个大小为m的背包的方案数。

      如果直接证明做,时间复杂度会超时,所以我们先计算出,所有的n/2大小背包的方案数,如果我们此时把x和y的物品全部从这个背包中减去,就得到了不含x和y的背包的方案数,这个方案数和含xy是一样的。每次减完后再加回去。

      而对于x和y相等的情况下,n/2的背包要么含x,要么不含x,所以此时背包数就等于f*2.

      注意背包如果为空,则不要处理,否则会出错,加减的顺序也要注意。

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll; 
    const int maxn=100010;
    const ll p=1e9+7;
    int n,m;
    char s[maxn];
    ll bur[60];
    ll fac[maxn],inv[maxn],ans[100][100],dp[maxn],tep[maxn];
    int find(char c){
        if(c>='A'&&c<='Z')return c-'A'+26;
        return c-'a';
    }
    void init(){
        clr(bur,0),clr(dp,0),clr(inv,0);
    }
    ll qpow(ll a,ll b){
        a%=p;
        ll res=1;
        while(b){
            if(b&1)res*=a;
            res%=p;
            a*=a,a%=p;
            b>>=1;
        }
        return res;
    }
    int main(){
        while(scanf("%s",s+1)!=EOF)
        {
            init();
            n=strlen(s+1);
            for(int i=1;i<=n;i++)
            {
                bur[find(s[i])]++;
            }
            fac[0]=1;
            for(int i=1;i<=n;i++)
            {
                fac[i]=i*fac[i-1]%p;
            }
            ll num=fac[n/2]*fac[n/2]%p;
            for(int i=0;i<52;i++)
            {
                if(bur[i]==0)continue;
                inv[i]=qpow(fac[bur[i]],p-2);
                num=num*inv[i]%p;
            }
            // printf("num:%lld
    ",num);
            dp[0]=1;
            for(int i=0;i<52;i++)
            {
                if(!bur[i])continue;
                for(int j=n/2;j>=bur[i];j--)
                {
                    dp[j]+=dp[j-bur[i]];
                    dp[j]%=p;
                }
            }
            for(int i=0;i<52;i++)
            {
                ans[i][i]=dp[n/2];
            }
            for(int i=0;i<52;i++)
            {
                if(!bur[i])continue;
                for(int j=0;j<=n/2;j++)tep[j]=dp[j];
                for(int j=bur[i];j<=n/2;j++)
                {
                    tep[j]=(tep[j]-tep[j-bur[i]]+p)%p;
                }
                for(int k=i+1;k<52;k++)
                {
                    if(!bur[k])continue;
                    for(int j=bur[k];j<=n/2;j++)
                    {
                        tep[j]=(tep[j]-tep[j-bur[k]]+p)%p;
                    }
                    ans[i][k]=ans[k][i]=tep[n/2]*2%p;
                    for(int j=n/2;j>=bur[k];j--)
                    {
                        tep[j]=(tep[j]+tep[j-bur[k]])%p;
                    }
                    
                }
            }
            cin>>m;
            int x,y;
            while(m--)
            {
                scanf("%d%d",&x,&y);
                x=find(s[x]),y=find(s[y]);
                printf("%lld
    ",num*ans[x][y]%p);
            }
        }
        
    }
    View Code

    E. Tree

    补题。

    题意:

      给出一棵树,q次询问,每次询问给出k个树上的点,然后给出r,以r这个节点为根,将这k个点分成m组,要求组内的点,任意两点不能有祖先关系。求方案分配数。

    思路:

      参考了官方题解和Dup4的博客,加上了自己的一些理解。

      当我们固定根节点为1的时候,我们设h[ i ]表示已经有几个 i 的祖先节点放入这些集合了。

      $dp[ i ]  [ j ]$ 表示将前 i 个点放入 j 个集合的方案数。

      得到转移方程$dp[ i ] [ j ] =dp[ i -1 ][  j ]*(j - h[ i ])+dp[ i-1 ][ j-1 ]$。

      这个方程的后半部分很好理解,就是把前i-1个点放完后,新开一个背包,把点放进去。

      而前半部分,就是要把这个点放入已经存在的背包里面了,那(j-h[ i ] )是什么意思呢,因为我们能把当前节点放入所有没有他祖先节点的集合里,而他的祖先节点必定也不是在同一个组里的,所以方案数就是这个。并且只要我们将h[ i ]从小到大排序,然后按序插入,这样就可以保证所有祖先节点都比子节点先进行dp。

      那怎么处理这个h[ i ] 呢,还是对于固定1为根节点的来说,如果我们先处理好dfs序,然后把每个节点的子树节点用BIT全部加1,那么对于i这个点的值,就是i的祖先节点的值加上本身了。

      现在考虑怎么把固定根为1的树推广向普通树,关键还是这个h[ i ],那给出r,我们可以先求出r这个点的祖先节点数量,在求出每个x节点和r的lca,记做y,求出y的祖先节点个数,然后图上画一画就知道怎么转换了。

      求lca这里用了树链剖分。

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll; 
    const int maxn=100010;
    const ll p=1e9+7;
    int n,q,dep[maxn],son[maxn],siz[maxn],lp[maxn],rp[maxn],top[maxn],fa[maxn];
    int cnt;
    vector<int >ve[maxn];
    int k,m,r,vec[maxn],a[maxn];
    ll dp[maxn],h[maxn];
    bool vis[maxn];
    void init(){
        for(int i=1;i<=n;i++)ve[i].clear();
        cnt=0;
        clr(a,0);
    }
    void dfs(int u,int f){
        siz[u]=1;
        son[u]=0;
        fa[u]=f;
        for(int i=0;i<ve[u].size();i++)
        {
            int v=ve[u][i];
            if(v==f)continue;
            dep[v]=dep[u]+1;
            dfs(v,u);
            siz[u]+=siz[v];
            if(son[u]==0||siz[v]>siz[son[u]]){
                son[u]=v;
            }
        }
    }
    void gettop(int u,int to){
        lp[u]=++cnt;
        top[u]=to;
        if(son[u]==0){
            rp[u]=cnt;
            return;
        }
        gettop(son[u],to);
        for(auto v:ve[u]){
            if(v != fa[u] &&v!=son[u]){
                gettop(v,v);
            }
        }
        rp[u]=cnt;
    }
    int lca(int u,int v){
        while(top[u]!=top[v]){
            if(dep[top[u]] < dep[top[v]])swap(u,v);
            u=fa[top[u]];
        }
        if(dep[u]>dep[v])swap(u,v);
        return u;
    }
    int lowbit(int x){
        return x & (-x);
    }
    void add(int x,int val){
        while(x<=n){
            a[x]+=val;
            x+=lowbit(x);
        }
    }
    void update(int l,int r,int val){
        add(l,val),add(r+1,-val);
    }
    int getsum(int x){
        int res=0;
        while(x>0){
            res+=a[x];
            x-=lowbit(x);
        }
        return res;
    }
    int main(){
        while(cin>>n>>q)
        {
            init();
            for(int i=1;i<n;i++)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                ve[u].push_back(v);
                ve[v].push_back(u);
            }
            dfs(1,0);
            gettop(1,1);
            while(q--)
            {
                
                scanf("%d%d%d",&k,&m,&r);
                for(int i=1;i<=m;i++)dp[i]=0;
                dp[0]=1;
                for(int i=1;i<=k;i++)
                {
                    scanf("%d",&vec[i]);
                    vis[vec[i]]=1;
                    update(lp[vec[i]],rp[vec[i]],1);
                }
                int ancnum=getsum(lp[r]);
                for(int i=1;i<=k;i++)
                {
                    int x=vec[i];
                    int y=lca(x,r);
                    h[x]=getsum(lp[x])+ancnum-2*getsum(lp[y])+(vis[y])-1;
                }
                for(int i=1;i<=k;i++)
                {
                    vis[vec[i]]=0;
                    update(lp[vec[i]],rp[vec[i]],-1);
                }
                sort(vec+1,vec+1+k,[](int x,int y){
                    return h[x]<h[y];
                });
                if(h[vec[k]]>=m)puts("0");
                else{
                    
                    for(int i=1;i<=k;i++)
                    {
                        int x=vec[i];
                        for(int j=min(i,m);j>=0;j--)
                        {
                            if(j<=h[x])dp[j]=0;
                            else{
                                dp[j]=(dp[j]*(j-h[x]))%p+dp[j-1];
                            }
                        }
                    }
                    ll ans=0;
                    for(int i=1;i<=m;i++)ans=(ans+dp[i])%p;
                    printf("%lld
    ",ans);
                    
                }
            }
        }
    }
    View Code
  • 相关阅读:
    数据库——表操作(5)
    数据库——存储引擎(4)
    数据库——库操作(3)
    数据库——初始mysql语句(2)
    数据库——初识数据库(1)
    并发编程——协程(5)
    并发编程——IO模型(6)
    并发编程——多线程(4)
    并发编程——多进程——multiprocessing开启进程的方式及其属性(3)
    并发编程——多进程——理论(2)
  • 原文地址:https://www.cnblogs.com/mountaink/p/10351663.html
Copyright © 2020-2023  润新知