HDU1880
给出对应的字符串,需要建立相应的双向映射。也就是输入first串可以得出对应的second串,输入second串可以得出对应的first串
数据有100000 ,用map<string,string>模拟爆内存。
使用 BKDRHash 哈希函数进行哈希
// BKDR Hash Function
unsigned int BKDRHash(char *str)
{
unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
unsigned int hash = 0;
while (*str)
{
hash = hash * seed + (*str++);
}
return (hash & 0x7FFFFFFF);
}
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 100010;
const int H = 100007;
struct node{
char que[25];
char ans[85];
int next;
};
node nodeA[N], nodeB[N];
int curA,curB;
int hashTableA[N] , hashTableB[N];
void initHash(){
for(int i=0;i<H;i++){
hashTableA[i] = -1;
hashTableB[i] = -1;
}
curA = 0;
curB = 0;
}
unsigned int getHash(char *s){
unsigned int seed = 131;
unsigned int hash = 0;
while(*s){
hash = hash * seed + *s++;
}
return (hash & 0x7fffffff) % H;
}
void insertHash(char *que,char *ans){
unsigned int h;
h = getHash(que);
strcpy(nodeA[curA].que, que);
strcpy(nodeA[curA].ans, ans);
nodeA[curA].next = hashTableA[h];
hashTableA[h] = curA;
++curA;
h = getHash(ans);
strcpy(nodeB[curB].que,que);
strcpy(nodeB[curB].ans,ans);
nodeB[curB].next = hashTableB[h];
hashTableB[h] = curB;
++curB;
}
int searchHashA(char *que){
unsigned int h = getHash(que);
int next = hashTableA[h];
while(next != -1){
if(strcmp(que,nodeA[next].que) == 0) return next;
next = nodeA[next].next;
}
return -1;
}
int searchHashB(char *ans){
unsigned int h = getHash(ans);
int next = hashTableB[h];
while(next != -1){
if(strcmp(ans, nodeB[next].ans) == 0) return next;
next = nodeB[next].next;
}
return -1;
}
int main(){
char str[120], que[25], ans[85],qlen ,alen;
int n,res;
initHash();
while(gets(str)){
if(str[0] == '@') break;
qlen = 0;
for(int i=1;str[i] != ']';++i){
que[qlen++] = str[i];
}
que[qlen] = 0;
alen = 0;
for(int i=qlen+3; str[i] != 0; ++i){
ans[alen++] = str[i];
}
ans[alen] = 0;
insertHash(que,ans);
}
scanf("%d",&n);
getchar();
while(n--){
gets(str);
if(str[0] == '['){
qlen = strlen(str);
str[qlen - 1] = 0;
res = searchHashA(str + 1);
if(res == -1) printf("what?\n");
else printf("%s\n",nodeA[res].ans);
}else{
alen = strlen(str);
res = searchHashB(str);
if(res == -1) printf("what?\n");
else printf("%s\n",nodeB[res].que);
}
}
return 0;
}
POJ1743
题意:有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题。“主题”是整个音符序列的一个子串,它需要满足如下条件:
后缀数组可解,
这里用到88进制取模进行哈希函数
想出这种方法的作者连接 http://blog.renren.com/share/283538506/12293487302/0
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
using namespace std;
const int maxh = 10007;
const int maxn = 20010;
typedef long long ll;
typedef unsigned long long ull;
#define mem(a,x) memset(a,x,sizeof a)
struct HASHMAP{
int head[maxh] , next[maxn] , size;
ull state[maxn];
int f[maxn];
void init(){
size = 0;
mem(head,-1);
}
int insert(ull val,int id){
int h = val % maxh;
for(int i=head[h]; i != -1; i = next[i]){
if(val == state[i]) return f[i];
}
f[size] = id;
state[size] = val;
next[size] = head[h];
head[h] = size++;
return f[size - 1];
}
};
HASHMAP H;
const int SEED = 13331;
ull P[maxn];
ull S[maxn];
int A[maxn];
int n;
bool check(int x){
H.init();
for(int i=x;i<n;i++)
if(H.insert(S[i] - S[i-x]*P[x],i ) < i - x)
return true;
return false;
}
int main(){
P[0] = 1;
for(int i=1;i<maxn;i++)
P[i] = P[i-1] * SEED; // unsigned long long 自动取模
while(scanf("%d",&n) && n){
for(int i=1;i<=n;i++)
scanf("%d",&A[i]);
for(int i=1;i<n;i++)
A[i] = A[i + 1] - A[i];
S[0] = 0;
for(int i=1;i<n;i++)
S[i] = S[i-1] * SEED + A[i];
int ans = 0;
int l = 4, r = n - 1;
while(l <= r){
int mid = (l + r) >>1;
if(check(mid)){
ans = mid;
l = mid +1;
}else
r = mid -1;
}
if(ans < 4) ans = -1;
ans++;
printf("%d\n",ans);
}
return 0;
}
SCU4438 字符串hash ,好题
通过构造hash表,记录模式串的hash值,然后对主串按顺序遍历每个字符,并存入数组stack,并算出当前串的hash值,通过hash[i] - hash[i - len]*hashpow 算出当前子串是否与模式串hash值相等,相等就将数组stack中的下标回退len长度,实现删除匹配的串。
细节还有待推敲
代码
#include<cstdio>
#include<algorithm>
#include<map>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<cstdlib>
#include<iostream>
using namespace std;
#define maxn 5000006
typedef unsigned long long ll;
ll hash = 100007;
ll hash_w;
ll hash_p [maxn];
ll hash_pow[maxn];
char p[maxn], w[maxn];
char stack[maxn];
int len ;
void init(){
hash_pow[0] = 1;
for(int i=1;i<maxn;i++)
hash_pow[i] = hash_pow[i -1] *hash;
}
bool check(int pos){
if(pos >= len && hash_p[pos] -
hash_p[pos - len] *hash_pow[len] == hash_w ){
// cout<<pos<<" "<<hash_p[pos] <<" "<<hash_p[pos - len] *hash_pow[len]<<endl;
return true;
}
return false;
}
int main(){
init();
while(~scanf("%s%s",w,p)){
len = strlen(w);
//模式串的hash值
hash_w = 0;
for(int i=0;*(w + i);i++){
hash_w = hash_w * hash + *(w + i);
// cout<<hash_w<<" xx ";
}
// cout<<endl;
int top = 0;
for(int i=0; *(p + i); i++){
stack[top++] = *(p + i);
hash_p[top] = hash_p[top - 1]*hash + *(p + i);
if(check(top)) top -= len;
}
for(int i=0;i<top;i++)
printf("%c",stack[i]);
puts("");
}
return 0;
}
HDU1280整数hash 水题
#include<cstdio>
#include<algorithm>
#include<map>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<cstdlib>
#include<iostream>
using namespace std;
#define maxn 5000006
typedef unsigned long long ll;
#define mem(a,x) memset(a,x,sizeof a)
int arr[3333];
int vis[10010];
int main(){
int n,m;
while(scanf("%d%d",&n,&m) != EOF){
mem(vis,0);
for(int i=0;i<n;i++){
scanf("%d",&arr[i]);
}
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
vis[arr[i] + arr[j] ] ++;
}
}
bool isfirst = true;
for(int i=10000;i>=0;i--){
if(!m)break;
while(m && vis[i]){
if(isfirst)
printf("%d",i);
else
printf(" %d",i);
isfirst = false;
m--;
vis[i]--;
}
}
puts("");
}
return 0;
}
HDU1496
a*x1^2+b*x2^2+c*x3^2+d*x4^2=0
给出这样一个式子,给出a,b,c,d.求有多少解, abcd范围 [-50,50] x1 - x4 [-100,100];
hash,四层循环改成二层循环,通过数组映射判断是否冲突,冲突就说明匹配,说明有解。另外特殊情况该优化的还要优化,否者会超时。
#include<cstdio>
#include<algorithm>
#include<map>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<cstdlib>
#include<iostream>
using namespace std;
typedef unsigned long long ll;
#define mem(a,x) memset(a,x,sizeof a)
//-50*(10000) *2 = 1e 6;
const int maxn = 1e6 + 2;
int vis[2000010]; //2e6 + 10;
int main(){
int a,b,c,d;
while(scanf("%d%d%d%d", &a,&b,&c,&d) != EOF){
if(a > 0 && b> 0 && c > 0 && d > 0){//没有这句就超市了
puts("0");
continue;
}
mem(vis,0);
for(int i=1;i<=100;i++){
for(int j=1;j<=100;j++){
vis[a*i*i + b*j*j + maxn ] ++;
}
}
int ans = 0;
for(int i=1;i<=100;i++){
for(int j=1;j<=100;j++){
ans += vis[-(c*i*i + d*j*j)+maxn];
}
}
// 每个i ,j都是可正 可负,2 * 2 * 2 * 2 == 16
printf("%d\n",ans*16);
}
return 0;
}
ACDREAM 1726
给出N个数 和一个数 H ,从N个数中选择任意多个数,问有多少种选择使得选的数的和 等于H 。
N <=40 H <= 1e9
1e9需要哈希一下。
N = 40 折半之后哈希就可以了。
二分数据,数据减半后,时间复杂度 有 2 ^ 40 变为 2 ^ 20;
再用HASH判断是否满足
#include<cstdio>
#include<algorithm>
#include<map>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<cstdlib>
#include<iostream>
using namespace std;
typedef long long ll;
#define mem(a,x) memset(a,x,sizeof a)
const int maxn = 1<<20; // 1048576
const int hash = 1000007; //开多大的hash
/*
3 1000010
next记录的是之前的head
head代表着数据在a数组中的位置。
head始终代表着头结点
*/
struct hashmap{
ll a[maxn]; //映射入的数组
int head[hash] , next[maxn],size;
void init(){
mem(head,-1);
size = 0;
}
/*
取模相同的数,存入a中之后,可以通过next遍历找到head进而找到对应a[i];
实现了取模相同的数放到邻接表里一样的查询。
*/
bool find(ll val){ //查找一个元素是否在hash表中
int tmp = (val % hash + hash) % hash;
for(int i=head[tmp]; i != -1;i = next[i]){
if(val == a[i]) return true;
}
return false;
}
void add(ll val){ // 添加元素到hash表
int tmp = (val % hash + hash) %hash;
if(find(val)) return ;
a[size] = val;
next[size] = head[tmp];
head[tmp] = size ++;
}
}h1;
int n,m,num[55];
int main(){
//
// h1.init();
// h1.add(3);
// h1.add(4);
// h1.add(5);
// h1.add(6);
// h1.add(1000010);
// h1.add(2000017);
while(~scanf("%d%d",&n,&m)){
h1.init();
for(int i=0;i<n;i++) scanf("%d",num+i);
int t = n/2;
// 将t种取或者不取 映射为二进制数,进行枚举
for(int i=0;i<(1<<t);i++){
ll sum = 0;
for(int j=0;j < t;j++){
if(i & (1<<j)){
sum += num[j]; //加上选中的数
}
}
if(sum > m) continue;
h1.add(sum);
}
int tt = n - t; //枚举剩下的数
int flag = 0;
for(int i=0;i<(1<<tt);i++){
ll sum = 0;
for(int j=0;j<tt;j++){
if(i & (1<<j))
sum += num[t + j]; //加上剩下的数中符合条件的
}
if(sum > m) continue;
if(h1.find(m - sum)){
flag = 1; break;
}
}
if(flag)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}