ACM中的Hash小结

在ACM中Hash的主要用途有:

  1. 记忆化搜索中用来压缩状态,从而节省空间(类似状压dp)
  2. 初始化某些数据,方便之后的算法进行处理(搜索,dp等)
  3. 用来唯一的标记一个字符串(像大数),用Hash处理后同时能O(1)的得出某个子串的Hash值

具体题目:
待补充完整…

类型二

入门题:
待补充…

进阶题:
2021 ICPC昆明站 K Riichi!!
题目:(太长了,这里就不放了)

题意:
给你一手14张的手牌,判断打掉打哪一张听牌并且输出对应的听的牌,如果已经胡了的话直接输出Tasumo
胡牌的条件是有两张一样的牌,剩下的牌要全么是三张一样的牌或者顺子(例:七八九条)要注意的是,单一种类的牌的数量没有上限,不像正常的只有四张(没有注意,给我调傻了。。。)

思路:
可以将所有的牌分为四类:万,条,筒,字。对于每一类,忽略类与类的不同,除字类牌外,其实他们的胡牌条件都相同。那么我们可以先搜索出所有胡牌条件的子集(不超过1<<23,也就是9类加14张),最后判断的时候只需要枚举每张牌对于答案的影响,易证明能满足条件。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn=1<<23|5;

bool ok[maxn];

int cnt[9];
int a[36];
int tot=0;

int get_hash(){
    tot=0;
    int ans=0;
    for(int i=0;i<9;i++){
        ans<<=1;
        ans+=1;
        ans<<=cnt[i];
        tot+=cnt[i];
    }
    return ans;
}

void dfs(int p){
    int cal=get_hash();
    if(ok[cal])
        return ;
    ok[cal]=1;
    for(;p<=8;p++){
        if(p<=6&&tot<=11){
            cnt[p]++,cnt[p+1]++,cnt[p+2]++,tot+=3;
            dfs(p);
            cnt[p]--,cnt[p+1]--,cnt[p+2]--,tot-=3;
        }
        if(tot<=11){
            cnt[p]+=3,tot+=3;
            dfs(p);
            cnt[p]-=3,tot-=3;
        }
        if(tot%3==0&&tot<=12){
            cnt[p]+=2,tot+=2;
            dfs(p);
            cnt[p]-=2,tot-=2;
        }
    }
}
bool ck(){
    int sum=0;
    memcpy(cnt,a,sizeof(cnt));
    if(!ok[get_hash()])
        return 0;
    sum+= tot%3==2;
    memcpy(cnt,a+9,sizeof(cnt));
    if(!ok[get_hash()])
        return 0;
    sum+= tot%3==2;
    if(sum>=2)
        return 0;
    memcpy(cnt,a+18,sizeof(cnt));
    if(!ok[get_hash()])
        return 0;
    sum+= tot%3==2;
    if(sum>=2)
        return 0;
    memcpy(cnt,a+27,sizeof(cnt));
    if(!ok[get_hash()])
        return 0;
    for(int i=0;i<7;i++){
        if(cnt[i]>=3)
            cnt[i]-=3;
        if(cnt[i]>=2)
            cnt[i]-=2,sum++;
        if(cnt[i])
            return 0;
    }
    if(sum>=2) return 0;
    return 1;
}

string get_c(int x){
    string ans="";
    ans+='0'+((x%9)+1);
    if(x<9) ans+='w';
    else if(x<18) ans+='b';
    else if(x<27) ans+='s';
    else ans+='z';
    return ans;
}

int main()
{
    int t;
    dfs(0);
    scanf("%d",&t);
    while(t--){
        string s;
        cin>>s;
        memset(a,0,sizeof(a));
        for(int i=0;i<s.size();i+=2){
            if(s[i+1]=='w') a[s[i]-'0'-1]++;
            else if(s[i+1]=='b') a[s[i]-'0'+9-1]++;
            else if(s[i+1]=='s') a[s[i]-'0'+18-1]++;
            else a[s[i]-'0'+27-1]++;
        }
        if(ck()){
            puts("Tsumo!");
            continue;
        }
        int ans=0;
        string xxx="";
        for(int i=0;i<34;i++){
            if(!a[i])
                continue;
            int sum=0;
            a[i]--;
            for(int j=0;j<34;j++){
                if(i==j)
                    continue;
                a[j]++;
                if(ck()){
                    sum++;
                    if(sum==1) ans++,xxx+=get_c(i)+" ";
                    xxx+=get_c(j);
                }
                a[j]--;
            }
            if(sum)
                xxx+='\n';
            a[i]++;
        }
        printf("%d\n",ans);
        if(ans)
        cout<<xxx;
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值