1.hdu1800 Flying to the Mars
题意:给你n个数,输出出现最多次数数的次数。
思路:由于每个数长度小于30,需要对这些数用字符串读入后,用哈希函数对应一个值,开放地址法解决冲突。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=1000005;
int inf=0x3f3f3f3f;
const int maxn=7003;
int Hash[maxn],Count[maxn],n,maxit;
LL mod=1e9+7;
inline int ELFhash(char *key)
{
unsigned long h=0;
while(*key)
{
h=(h<<4)+*key++;
unsigned long g=h&0xf0000000L;
if(g)
h^=g>>24;
h&=~g;
}
return h%N;//%N?o
}
inline void hashit(char *s)
{
int k;
while(*s=='0') s++;
k=ELFhash(s);
int t=k%maxn;
while(Hash[t]!=k&&Hash[t]!=-1)
t=(t+1)%maxn;
if(Hash[t]==-1){
Count[t]=1,Hash[t]=k;
}
else if(++Count[t]>maxit)
maxit=Count[t];
return;
}
int main()
{
int n;
char str[100];
while(~scanf("%d",&n))
{
memset(Hash,-1,sizeof(Hash));
memset(Count,0,sizeof(Count));
getchar();
maxit=1;
for(int i=0;i<n;i++)
{
gets(str);
hashit(str);
}
cout<<maxit<<endl;
}
return 0;
}
醉了…说好数字长度30,直接map也能过…
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
while(~scanf("%d",&n))
{
map<int,int>mp;
int maxx=0;
for(int i=0;i<n;i++)
{
int d;scanf("%d",&d);
mp[d]++;
maxx=max(maxx,mp[d]);
}
printf("%d\n",maxx);
}
}
2.poj2549 Sumsets
题意:给n个数,找出一个最大的数d,满足a+b+c=d.a,b,c,d都是这n个数里的。这里n<1000,-536870912
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define mm 100003
using namespace std;
bool flag;
int ha[mm],next[mm],s[1010],res,n;
struct Node
{
int x,y;
}node[500510];
void solve(int xx,int yy)
{
int key=(xx-yy<0?yy-xx:xx-yy)%mm;
int i=ha[key];
while(i!=-1)
{
//cout<<node[i].x<<node[i].y<<xx<<yy<<endl;
if((node[i].x+node[i].y)==(xx-yy)&&node[i].x!=xx&&node[i].x!=yy&&node[i].y!=xx&&node[i].y!=yy)
{
res=max(res,xx);
return;
}
i=next[i];
}
return;
}
int main()
{
while(scanf("%d",&n)&&n)
{
memset(ha,-1,sizeof(ha));
for(int i=0;i<n;i++)scanf("%d",&s[i]);
int c=0;sort(s,s+n);
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
{
node[c].x=s[i],node[c].y=s[j];
int key=(s[i]+s[j]<0?-s[j]-s[i]:s[i]+s[j])%mm;
next[c]=ha[key];
ha[key]=c;
c++;
}
res=-1000000000;
for(int i=n-1;i>=0;i--)
for(int j=n-1;j>=0;j--)
{
if(i==j) continue;
solve(s[i],s[j]);
}
if(res!=-1000000000) cout<<res<<endl;
else cout<<"no solution"<<endl;
}
}
这题还有一个很经典做法,中途相遇法,先排个序,枚举d-c,在剩下的搜索a+b,用的中途相遇法,很巧妙。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int inf=-600000000;
int a[1001];
int main()
{
int n;
while(scanf("%d",&n)&&n)
{
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
n--;
int ans=inf;
for(int i=n;i>=0;i--)
{
for(int j=n;j>=0;j--)
{
if(i==j)
continue;
int sum=a[i]-a[j];
for(int l=0,r=j-1;l<r;)
{
if(a[l]+a[r]==sum)
{
ans=a[i];
break;
}
if(a[l]+a[r]>sum)
r--;
else
l++;
}
if(ans!=inf)
break;
}
if(ans!=inf)
break;
}
if(ans==inf)
printf("no solution\n");
else
printf("%d\n",ans);
}
return 0;
}
3.HDU1496Equations
题目大意,给你a,b,c,d这4个数的值,然后问a*x1^2 + b*x2^2 + c*x3^2 + d*x4^2 = 0
的(x1,x2,x3,x4)解一共有多少种?
直接暴力n^4,n=1000,绝对TLE ,加上数据范围50*100000*2=100w可以开这么大的数组,所以直接hash表,很巧妙!分开两部分求和,结果正负用两个数组区别开,若两部分的和是0,则就加上那么多种,由于每个地方都可以正取负,最后乘以2^4.
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int maxn=50*100*100*2+100;
int inf=0x3f3f3f3f;
LL mod=1e9+7;
int hash_z[maxn],hash_f[maxn],res[101];
int main()
{
int a,b,c,d,sum;
for(int i=0;i<=100;i++) res[i]=i*i;
while(~scanf("%d %d %d %d",&a,&b,&c,&d))
{
memset(hash_z,0,sizeof(hash_z));
memset(hash_f,0,sizeof(hash_f));
if((a>0&&b>0&&c>0&&d>0)||(a<0&&b<0&&c<0&&d<0))
{
printf("0\n");
continue;
}
for(int i=1;i<=100;i++)
{
for(int j=1;j<=100;j++)
{
sum=a*res[i]+b*res[j];
if(sum>=0) hash_z[sum]++;
else hash_f[-sum]++;
}
}
int t=0;
for(int i=1;i<=100;i++)
{
for(int j=1;j<=100;j++)
{
sum=c*res[i]+d*res[j];
if(sum>0) t+=hash_f[sum];
else t+=hash_z[-sum];
}
}
printf("%d\n",t<<4);
}
}
大神精炼的代码,直接开了200w数组,加一个基值就不用考虑正负问题,也能一一对应。
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
int hash[2000011];
int main()
{
int i,l;
int a,b,c,d;
int ans;
while(scanf("%d%d%d%d",&a,&b,&c,&d)!=-1)
{
if(a*b>0 && b*c>0 && c*d>0) {printf("0\n");continue;}
memset(hash,0,sizeof(hash));
for(i=1;i<=100;i++)
for(l=1;l<=100;l++)
hash[a*i*i+b*l*l+1000000]++;
ans=0;
for(i=1;i<=100;i++)
for(l=1;l<=100;l++)
ans+=hash[-c*i*i-d*l*l+1000000];
printf("%d\n",16*ans);
}
return 0;
}
4 poj 2503
题意:输入10w个字典词汇。再输入字典词汇对应的方言,问这个词汇是否存在字典里,存在输出,不存在就输出“eh”.
题意很好理解,就是输入数据10w个,所以必须用字符串hash解决,推荐使用ELFhash函数,拉链发解决冲突,也可以保存后,用二分查找。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<map>
#include<iterator>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int maxn=100003;
int inf=0x3f3f3f3f;
int ELFhash(char *key)
{
unsigned long h=0;
while(*key){
h=(h<<4)+*key++;
unsigned long g=h&0Xf0000000L;
if(g)
h^=g>>24;
h&=~g;
}
return h%maxn;
}
int ha[maxn],next[maxn];
struct Node
{
char str1[15],str2[15];
}node[maxn];
int main()
{
char s[30];
int n=0;
memset(ha,-1,sizeof(ha));
while(gets(s))
{
if(sscanf(s,"%s%s",node[n].str1,node[n].str2)!=2)
break;
else
{
int key=ELFhash(node[n].str2);
next[n]=ha[key];
ha[key]=n;
n++;
}
}
while(~scanf("%s",s))
{
int key=ELFhash(s);
int i=ha[key];
while(i!=-1)
{
if(strcmp(s,node[i].str2)==0)
break;
i=next[i];
}
if(i==-1) printf("eh\n");
else printf("%s\n",node[i].str1);
}
}
二分
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<iostream>
const int maxn=1000010;
using namespace std;
typedef struct Str
{
char f[20],e[20];
}STR;
STR str[maxn];
int t=0;
int cmp(const void *a, const void *b)
{
return strcmp((*(STR *)b).e, (*(STR *)a).e);
}
int binary_Search(char *s)
{
int l=0,r=t-1;
while(l<=r)
{
int mid=(l+r)/2;
if(strcmp(s,str[mid].e)==0)
return mid;
else if(strcmp(s,str[mid].e)>0) r=mid-1;
else l=mid+1;
}
return -1;
}
int main()
{
char s[30];
while(gets(s))
{
if(s[0]=='\0') break;
sscanf(s,"%s %s",str[t].f,str[t].e);
t++;
}
qsort(str,t,sizeof(STR),cmp);
while(gets(s))
{
int index=binary_Search(s);
if(index==-1) printf("eh\n");
else printf("%s\n",str[index].f);
}
return 0;
}
5.poj2002 Squares
题意:给你n个二维平面的点,问这些点能够成多少个不同的正方形。
思路:这题难点需要很好的数学功底:如何在二维平面坐标里,已知两点坐标,求可能构成的正方形的另两个点坐标,需要用到向量的旋转公式,或者证明下图三角形全等。
可以得到
**已知: (x1,y1) (x2,y2)
则: x3=x1+(y1-y2) y3= y1-(x1-x2) ,x4=x2+(y1-y2) y4= y2-(x1-x2)
或x3=x1-(y1-y2) y3= y1+(x1-x2) x4=x2-(y1-y2) y4= y2+(x1-x2)**
接下来就是,将每个点平方取余后进入哈希表,每两个点枚举,求得另两个点后在哈希表里查找。最后注意,这样求得是正方形每个边都计数了一次,导致重复,最后结果/4.
#include<map>
#include<queue>
#include<stack>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn=1010;
const int prime=1007;
int inf=0x3f3f3f3f;
ll mod=1e9+7;
int Hash[maxn],n;
struct Node
{
int x,y,next;
}node[maxn];
bool find_point(int a,int b)
{
int key=(a*a+b*b)%prime;
int i=Hash[key];
while(i!=-1)
{
if(node[i].x==a&&node[i].y==b) return true;
i=node[i].next;
}
return false;
}
int main()
{
while(scanf("%d",&n)&&n)
{
int ans=0;
memset(Hash,-1,sizeof(Hash));
for(int i=0;i<n;i++)
{
int a,b;scanf("%d %d",&a,&b);
int key=(a*a+b*b)%prime;
node[i].x=a,node[i].y=b;
node[i].next=Hash[key];
Hash[key]=i;
}
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
{
int x3=node[i].x+(node[i].y-node[j].y);
int y3=node[i].y-(node[i].x-node[j].x);
int x4=node[j].x+(node[i].y-node[j].y);
int y4=node[j].y-(node[i].x-node[j].x);
if(find_point(x3,y3)&&find_point(x4,y4)) ans++;
}
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
{
int x3=node[i].x-(node[i].y-node[j].y);
int y3=node[i].y+(node[i].x-node[j].x);
int x4=node[j].x-(node[i].y-node[j].y);
int y4=node[j].y+(node[i].x-node[j].x);
if(find_point(x3,y3)&&find_point(x4,y4)) ans++;
}
printf("%d\n",ans>>2);
}
}