hdu 4185 Oil Skimming 二分图匹配

Oil Skimming

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/** Aug 24, 2015 11:15:57 AM
* PrjName:hdu4185
* @author Semprathlon
*/
import java.io.*;
import java.util.*;
public class Main {

/**
* @param args
*/
static char[][] mp;
//static int[][] adj;
static int[] match;
static boolean[] vis;
static int n,cnt,sum;
final static int[][] dir={ {-1,0},{1,0},{0,-1},{0,1}};
final static int maxn=605;
static Vector<Integer>[] adj=new Vector[maxn*maxn>>1];
static HashMap<Integer, Integer> sta=new HashMap<Integer,Integer>();
static HashMap<Integer, Integer> stb=new HashMap<Integer,Integer>();
static int geta(Pt p){
int hash=p.hashCode();
if (sta.containsKey(hash))
return sta.get(hash);
else{
sta.put(hash, ++cnt);
return cnt;
}
}
static int getb(Pt p){
int hash=p.hashCode();
if (stb.containsKey(hash))
return stb.get(hash);
else{
stb.put(hash, ++sum);
return sum;
}
}
static boolean cango(int x,int y){
if (x<0||x>=n||y<0||y>=n||mp[x][y]!='#') return false;
return true;
}
static boolean dfs(int u){
for(int v:adj[u]){
if (vis[v]) continue;
vis[v]=true;
if (match[v]<0||dfs(match[v])){
match[v]=u;
return true;
}
}
return false;
}
static int maxmatch(){
int res=0;
Arrays.fill(match, -1);
for(int i=1;i<=cnt;i++){
Arrays.fill(vis, false);
if (dfs(i)) res++;
}
return res;
}
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
InputReader in=new InputReader(System.in);
PrintWriter out=new PrintWriter(System.out);
for(int i=0;i<maxn*maxn>>1;i++) adj[i]=new Vector<Integer>();
int T=in.nextInt(),cas=0;

while(T-->0){
n=in.nextInt();
mp=new char[n][n];
for(int i=0;i<n*n>>1;i++) adj[i].clear();
sta.clear();stb.clear();cnt=sum=0;
for(int i=0;i<n;i++){
String s=in.next();
for(int j=0;j<n;j++)
mp[i][j]=s.charAt(j);
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if (mp[i][j]=='#'){
Pt p=new Pt(i, j,n);
for(int k=0;k<4;k++){
int x=i+dir[k][0];
int y=j+dir[k][1];
if (((x+y)&1)>0&&cango(x,y)){
Pt q=new Pt(x, y,n);
adj[geta(p)].add(getb(q));
//adj[q.hashCode()].add(p);
}
}
}
match=new int[sum+1];
vis=new boolean[sum+1];
out.println("Case "+(++cas)+": "+maxmatch());
}
out.flush();
out.close();
}

}
class Pt{
int x,y,n;
Pt(int _x,int _y,int _n){
x=_x;y=_y;n=_n;
}
Pt(int hash,int _n){
n=_n;
y=hash%n;
x=hash/n;
}
public int hashCode(){
return x*n+y;
}
}
class InputReader{
public BufferedReader reader;
public StringTokenizer tokenizer;

public InputReader(InputStream stream){
reader = new BufferedReader(new InputStreamReader(stream), 32768);
tokenizer = null;
}

public String next(){
while(tokenizer == null || !tokenizer.hasMoreTokens()){
try{
tokenizer = new StringTokenizer(reader.readLine());
}catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}

public int nextInt() {
return Integer.parseInt(next());
}

public long nextLong() {
return Long.parseLong(next());
}

}

折腾了过长的时间,原因:
这不是通常意义上的可随意匹配的二分图。
既然是二分图,就有把节点分为两类的依据。
由题中给定的结合规则,一定是一个(x+y)为偶数的点与一个(x+y)为奇数的点相匹配,且是相邻点的匹配。
所以会将两类点分别加入两个表中,并进行hash操作节约存储空间。
“奇”的点总是不少于“偶”的点?

hdu 4821 String hash乱搞

String

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

Problem Description

Given a string S and two integers L and M, we consider a substring of S as “recoverable” if and only if
(i) It is of length M*L;
(ii) It can be constructed by concatenating M “diversified” substrings of S, where each of these substrings has length L; two strings are considered as “diversified” if they don’t have the same character for every position.

Two substrings of S are considered as “different” if they are cut from different part of S. For example, string “aa” has 3 different substrings “aa”, “a” and “a”.

Your task is to calculate the number of different “recoverable” substrings of S.

Input

The input contains multiple test cases, proceeding to the End of File.

The first line of each test case has two space-separated integers M and L.

The second ine of each test case has a string S, which consists of only lowercase letters.

The length of S is not larger than 10^5, and 1 ≤ M * L ≤ the length of S.

Output

For each test case, output the answer in a single line.

Sample Input

3 3
abcabcbcaabc

Sample Output

2

Source

2013 Asia Regional Changchun

纯粹是寻找一个最佳的hash姿势?而且还要懂得合适的时间优化?
真的TLE了好几次,现场赛的难点
枚举字串起点不必从头找到尾,因为向后滚的操作涵盖了i>=l以后的字串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include<cstdio>
#include<cstring>
#include<memory.h>
#include<string>
#include<map>
#define CLEAR(a) memset((a),0,sizeof((a)))

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
const int maxn=1e5+10;
const ULL base=29;//prime

map<ULL,int> mp;

ULL nbase[maxn],ha[maxn];
char str[maxn];
//string s;

void init()
{
nbase[0]=1;
for(int i=1;i<maxn;i++) nbase[i]=nbase[i-1]*base;
}

inline ULL Hash(char *s,int len,ULL *_hash) //按各个后缀hash
{
_hash[len]=0;
for(int i=len-1;i>=0;i--)
_hash[i]=_hash[i+1]*base+s[i]-'a';
}

inline ULL Get(ULL *_hash,int pos,int len)
{
return _hash[pos]-_hash[pos+len]*nbase[len];
}

int main()
{
init();
int m,l;

while(~scanf("%d%d",&m,&l))
{
LL ans=0;
scanf("%s",str);
int len=strlen(str);
Hash(str,len,ha);
for(int i=0;i<=len-m*l&&i<l;i++) //此处不加条件i<l就TLE
{
mp.clear();
for(int j=i;j<i+m*l;j+=l)
{
ULL h=Get(ha,j,l);
//cout<<h<<':'<<s.substr(j,l)<<endl;
mp[h]++;
}
if (mp.size()==m) ans++;
for(int j=i+m*l;j<=len-l;j+=l)
{
ULL h=Get(ha,j-m*l,l);
//cout<<h<<':'<<s.substr(j-m*l,l)<<endl;
mp[h]--;
if (!mp[h]) mp.erase(h);
h=Get(ha,j,l);
//cout<<h<<':'<<s.substr(j,l)<<endl;
mp[h]++;
if (mp.size()==m) ans++;
}
}
printf("%I64d\n",ans);
}
return 0;
}