Topcoder SRM 672 Div.2 题解

T1:

判断两个集合A、B的关系,包括A包含B,B包含A,A和B完全相同或者A和B不满足以上所有的关系。

那么模拟一下。可以开一个hsh数组标记一下,对于一个A[i],将hsh[a[i]]–;对于一个B[i],将hsh[B[i]]++。这样有一个好处,就是如果这个数即存在于a数组,也存在于b数组,可以相互抵消。最后分四种情况特判一下就可以啦。

代码如下:

string SetPartialOrder::compareSets(vector <int> a, vector <int> b) {
    int lena=a.size(),lenb=b.size();
    bool pdmin=0,pdmax=0;
    memset(hsh,0,sizeof(hsh));
    for (int i=1;i<=lena;i++) hsh[a[i-1]]--;
    for (int i=1;i<=lenb;i++) hsh[b[i-1]]++;
    for (int i=1;i<=100;i++) {
        if (hsh[i]<0) pdmin=1;
        if (hsh[i]>0) pdmax=1;
    }
    if (pdmin==1&&pdmax==0) return "GREATER";
    if (pdmin==1&&pdmax==1) return "INCOMPARABLE";
    if (pdmin==0&&pdmax==1) return "LESS";
    return "EQUAL";
}

T2

这题给定一个原串a和一个加密字符串b,你要根据这个加密规律求出某一加密串y的对应原串x。
如果不行就输出空串。

那么一看就只要简单的对于每一个b[i]做一个对于a[i]的映射就好了。
但是。。。我发现样例2死都过不去???
最后发现还有一个提示,没仔细看,突然秒懂,如果有25个字母已经一一对应了,对于最后一个加密字母,显然是可以求出它对应的原字母。
= =[汗]
那么既然如此,代码如下:

string SubstitutionCipher::decode(string a, string b, string y) {
    memset(hsh,0,sizeof(hsh));
    int lena=a.length(),lenb=b.length(),leny=y.length();
    s="";
    for (int i=1;i<=lena;i++) hsh[b[i-1]-'A'+1]=a[i-1]-'A'+1;
    int sum=0;
    for (int i=1;i<=26;i++) if (hsh[i]==0) sum++;
    if (sum==1) {
        for (int i=1;i<=26;i++) hsh1[hsh[i]]=1;
        int x=0;
        for (int i=1;i<=26;i++) if (!hsh1[i]) x=i;
        for (int i=1;i<=26;i++) if (hsh[i]==0) hsh[i]=x;
    }
    for (int i=1;i<=leny;i++)
    if (hsh[y[i-1]-'A'+1]==0) return "";
    else s=s+(char)(hsh[y[i-1]-'A'+1]+'A'-1);
    return s;
}

T3

这题题面极长。。。珂怕。
仔细一看,就是对于一个案件,侦探首先询问0,得出一串字符串,包含了他对于某一个人的怀疑程度,我们设为数组p。接下类侦探询问一个怀疑度最高的人x,如果这个人是凶手,就直接被抓滚粗;否则用这个人怀疑的程度来修正p,即对于每一个元素取 max(p[i],s[x][i]) m a x ( p [ i ] , s [ x ] [ i ] ) 。然后以此类推,直到抓到凶手。假设对于某一个人,如果他是凶手,抓到他的最小步数为ans[i]。那么我们要求的是(下标从0开始): n1i=0ans[i] ∑ i = 0 n − 1 a n s [ i ]
接下来就讲讲题解。
我们发现人数n比较小,只有18。而这个大小如果直接暴搜又不那么合适。我们自然就会想到状压DP。对于每一个人作为凶手,都DP一遍。
具体的DP过程比较简单,每个状态先修正它的p数组,然后直接推下一状态。如果遇到凶手就修正答案,然后continue。

代码如下:

int dp(int x,vector <string> s){
    memset(f,63,sizeof(f));
    int ret=f[0]; f[1]=0;
    for (int i=1;i<(1<<n);i++)
    if (i%2==1){
        memset(p,0,sizeof(p));
        if ((i&(1<<x-1))) {ret=min(ret,f[i]); continue;}
        for (int j=1;j<=n;j++)
        if ((i&(1<<j-1))>0)
        for (int k=2;k<=n;k++) p[k]=max(p[k],s[j-1][k-1]-'0');
        int maxx=0;
        for (int j=2;j<=n;j++) if (p[j]>maxx&&(i&(1<<j-1))==0) maxx=p[j];
        for (int j=2;j<=n;j++)
        if ((i&(1<<j-1))==0&&p[j]==maxx) {
            f[i+(1<<j-1)]=min(f[i+(1<<j-1)],f[i]+1);
        }
    }
    return ret;
}
int Tdetectived2::reveal(vector <string> s) {
    n=s.size(); ans=0;
    for (int i=2;i<=n;i++) {
        ans+=(i-1)*dp(i,s);
    }
    return ans;
}

总结:

今天的这场TC比较水,但是因为我比较菜,T3调了半天,交的时候只剩下370分左右了。还是要增加代码能力,提升姿势水平啊= =

ps:因为我太懒(不会),没把代码写到class里面,而且比较糟乱,尽量还是不看代码,自己独立思考吧。。。

2018.7.24

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值