在ACM中Hash的主要用途有:
- 记忆化搜索中用来压缩状态,从而节省空间(类似状压dp)
- 初始化某些数据,方便之后的算法进行处理(搜索,dp等)
- 用来唯一的标记一个字符串(像大数),用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;
}