题目链接:http://acm.neu.edu.cn/hustoj/problem.php?id=1588
题意:给出路由器的转发表,然后对于每组询问,输出应该从哪个端口出去。需要满足最长掩码匹配,如果有多个匹配,输出端口最小的那个
思路:开始用的map,无限T。赛后乱搞的hash。。hash也是乱搞的,冲突了就存到数组的下一个位置=。=
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a));
struct Node{
ll son;
int port;
};
const int mod = 109987;
Node node[33][110000];
bool vis[33][110000];
void hashh(int mask,ll a,int port){
int tmp = a%mod;
while(1){//cout<<tmp<<endl;
if(vis[mask][tmp] == 0){
vis[mask][tmp] = 1;
node[mask][tmp].son = a;
node[mask][tmp].port = port;
break;
}
else if(node[mask][tmp].son == a){
node[mask][tmp].port = min(node[mask][tmp].port,port);
break;
}
tmp ++;
if(tmp >= mod)tmp -= mod;
}
}
void find(ll tmp){
for(int i = 32;i >= 0;i --){
ll mask = ((1LL<<i)-1)*(1LL<<(32-i));
ll now = (tmp&mask);
int ff = now%mod;
while(1){
if(vis[i][ff] == 0)break;
else if(node[i][ff].son == now){
printf("%d\n",node[i][ff].port);
return;
}
ff ++;
if(ff >= mod)ff -=mod;
}
}
puts("65535");
}
int main(){
int T;
scanf("%d",&T);
while(T --){
memset(vis,0,sizeof(vis));
int n,m;
scanf("%d%d",&n,&m);
for(int i = 0;i < n;i ++){
int a,b,c,d,mask,port;
scanf("%d.%d.%d.%d/%d %d",&a,&b,&c,&d,&mask,&port);
ll tmp = ((a*256+b)*256+c)*256+(ll)d;
ll mm = ((1LL<<mask)-1)*(1LL<<(32-mask));
tmp = (tmp&mm);//cout<<tmp<<endl;
hashh(mask,tmp,port);//cout<<hh<<endl;
}
for(int i = 0;i < m;i ++){
int a,b,c,d;
scanf("%d.%d.%d.%d",&a,&b,&c,&d);
ll tmp = ((a*256+b)*256+c)*256+(ll)d;
find(tmp);
}
}
return 0;
}
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a));
struct Node{
ll son;
int port,mask;
};
const int mod = 99991;
vector<Node>vv[mod+1];
void hashh(int mask,ll a,int port){
int tmp = a%mod;
int siz = vv[tmp].size();
for(int i = 0;i < siz;i ++){
if(vv[tmp][i].son == a&&vv[tmp][i].mask == mask){
vv[tmp][i].port = min(vv[tmp][i].port,port);
return ;
}
}
Node t;
t.son = a;
t.port = port;
t.mask = mask;
vv[tmp].push_back(t);
}
void find(ll tmp){
for(int i = 32;i >= 0;i --){
ll mask = ((1LL<<i)-1)*(1LL<<(32-i));
ll now = (tmp&mask);
int ff = now%mod;
int siz = vv[ff].size();
for(int j = 0;j < siz;j ++){
if(vv[ff][j].mask == i&&vv[ff][j].son == now){
printf("%d\n",vv[ff][j].port);
return ;
}
}
}
puts("65535");
}
int main(){
int T;
scanf("%d",&T);
while(T --){
for(int i = 0;i < mod;i ++)vv[i].clear();
int n,m;
scanf("%d%d",&n,&m);
for(int i = 0;i < n;i ++){
int a,b,c,d,mask,port;
scanf("%d.%d.%d.%d/%d %d",&a,&b,&c,&d,&mask,&port);
ll tmp = ((a*256+b)*256+c)*256+(ll)d;
ll mm = ((1LL<<mask)-1)*(1LL<<(32-mask));
tmp = (tmp&mm);//cout<<tmp<<endl;
hashh(mask,tmp,port);//cout<<hh<<endl;
}
for(int i = 0;i < m;i ++){
int a,b,c,d;
scanf("%d.%d.%d.%d",&a,&b,&c,&d);
ll tmp = ((a*256+b)*256+c)*256+(ll)d;
find(tmp);
}
}
return 0;
}
这里用的mod 是99991,开始用的mod比较大直接就超时了,估计是因为每组case的时候都需要清空,如果mod太大的话会就会浪太多时间,所以还是得视情况YY,估计做题做多了就能有感觉了吧= 。=
*************************************************************************
然后是第二道题
链接:http://poj.org/problem?id=3349
题意:给n个雪花,雪花由六个数字构成,问有没有两个一样的雪花。两个雪花是一样的需要满足:假如a保持不动,那么b从某个点顺时针或逆时针转动,能找到一种情况满足6个数字均相等
思路:直接把6个数字相加作为hash的key值,然后正常hash乱搞,最后3700+ms水过= =,还是对效率不满意,于是接着乱搞,又T了。。。于是就暂时没有更快的代码。。status里面那些跑了300+ms的都是怎么搞的= =,太牛逼了
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a));
const int maxn = 100010;
int n;
struct Node{
int nn[6];
};
vector<Node>tt[maxn];
bool deng(int *a,int *b){
for(int i = 0;i < 6;i ++){
bool dd = 1;
for(int j = 0;j < 6;j ++)
if(a[j] != b[(i+j)%6]){dd = 0;break;}
if(dd)return 1;
}
for(int i = 0;i < 6;i ++){
bool dd = 1;
for(int j = 0;j < 6;j ++)
if(a[j] != b[(i-j + 6)%6]){dd = 0;break;}
if(dd)return 1;
}
return 0;
}
int a[6];
bool find(){
int sum = 0;
for(int i = 0;i < 6;i ++){
sum += a[i];
}//cout<<sum<<endl;
sum %= maxn;
int siz = tt[sum].size();
for(int i = 0;i < siz;i ++){
if(deng(a,tt[sum][i].nn))return 1;
}
Node tmp;
for(int i = 0;i < 6;i ++)
tmp.nn[i] = a[i];
tt[sum].push_back(tmp);
return 0;
}
int main(){
while(~ scanf("%d",&n)){
for(int i = 0;i < maxn;i ++)
tt[i].clear();
bool have = 0;
for(int i = 0;i < n;i ++){
for(int j = 0;j < 6;j ++)
scanf("%d",&a[j]);
have = find();//cout<<have<<endl;
if(have){
for(int j = i+1;j < n;j ++){
int b;
for(int jj = 0;jj < 6;jj ++)
scanf("%d",&b);
}
break;
}
}
if(have)puts("Twin snowflakes found.");
else puts("No two snowflakes are alike.");
}
return 0;
}
然后开始搞第三题:
链接:http://poj.org/problem?id=3349
题意:给出n个奶牛,奶牛拥有k种属性,每个奶牛的属性用十进制表示,换算成二进制就是具体的各个属性是否拥有。现在要找到一个最大的区间,这个区间中,如果将奶牛的属性用二进制表示,对于任意的两个属性A,B,拥有A属性的奶牛的个数和B是一样的。
思路:开始读错题,异或乱搞,发现不会(按照我理解的题意)。然后百度题解,才理解了题意。。解题思路还是挺巧妙地,首先维护一个从第一个奶牛到当前奶牛的各个属性的和,然后用其他的属性分别减去第一个属性,如果某个区间满足题目要求,那么这个区间的两个顶点经过之前的操作所形成的数组值应该是相同的(因为每个属性都增加了相同的个数),于是就要找到最远的两个一样的数组,用数组的和做为key,乱搞了一发hash。。
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
const int maxn = 999983;
struct Node{
int nn[31];
int id;
};
int ans;
int n,k;
vector<Node>vv[maxn];
void has(Node now){
unsigned int sum = 0;
for(int i = 0;i < k;i ++){
sum += now.nn[i];
}
sum = sum % maxn;//cout<<sum<<"aa"<<endl;
int siz = vv[sum].size();
for(int i = 0;i < siz;i ++){
bool deng = 1;
for(int j = 0;j < k;j ++)
if(now.nn[j] != vv[sum][i].nn[j]){deng = 0;break;}//cout<<"aaaaaaa";
if(deng){ans = max(ans,now.id - vv[sum][i].id);return;}
}
vv[sum].push_back(now);
}
int main(){
while(~scanf("%d%d",&n,&k)){
ans = 0;
for(int i = 0;i < maxn;i ++)
vv[i].clear();
Node in;
Node last;
for(int i = 0;i < k;i ++)last.nn[i] = 0;
last.id = 0;
has(last);
for(int i = 1;i <= n;i ++){
int a;
scanf("%d",&a);
for(int j = 0;j < k;j ++){
last.nn[j] += (a&1);
a >>= 1;
in.nn[j] = last.nn[j] - last.nn[0];
}
in.id = i;
has(in);
}
cout<<ans<<endl;
}
return 0;
}
/*************************************************************************************************************
乱入一个字符串hash 的代码(虽然之前教主好像讲过。。
// 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 % M);
}
然后根据上面的字符串的hash过了一个水题= =
链接:http://poj.org/problem?id=2503
思路:先给一堆成对字符串,然后输入一个空行,然后再给一对字符串,问这个字符串(开始是后面的)对应的那个字符串是什么,就是很简单的对应
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a));
struct Node{
char s[12];
char ans[12];
};
const int mod = 99991;
vector<Node>vv[mod];
unsigned int hh(char a[]){
unsigned int ans = 0;
unsigned int seed = 31;
while(*a){
ans = ans*seed + (*a ++);
}//cout<<ans%mod<<endl;
return ans % mod;
}
void has(char b[],char a[]){
unsigned int nn = hh(b);
Node tmp;
strcpy(tmp.s,b);
strcpy(tmp.ans,a);
vv[nn].push_back(tmp);
}
void find(char s[]){
unsigned int nn = hh(s);
int siz = vv[nn].size();
for(int i = 0;i < siz;i ++){
if(strcmp(vv[nn][i].s,s) == 0){
puts(vv[nn][i].ans);
return ;
}
}
puts("eh");
}
int main(){
char s[100];
char a[100],b[100];
while(gets(s)){
if(strlen(s) == 0)break;
int l = strlen(s);
for(int i = 0;i < l;i ++){
if(s[i] == ' '){
a[i] = '\0';
for(int j = i+1;j < l;j ++)
b[j-i-1] = s[j];
b[l-i-1] = '\0';
break;
}
a[i] = s[i];
}
has(b,a);
}
while(gets(s)){
find(s);
}
return 0;
}