微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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,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\n",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,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\n",ans);
    }
} 
View Code

 

D. Destroy the Colony

补。

题意:

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

思路:

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

  则答案应该是((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,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\n",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\n",num*ans[x][y]%p);
        }
    }
    
}
View Code

 

E. Tree

待补。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。