Southwestern Europe Regional Contest 2014 题解

时间:2017/9/8 题目8/10 Rank 5/150

体会:三星的题目和国内区域赛差距大,大多数题读懂题意就能做,所以静心读题是关键,套路性太深。

A:

题意:给出一个算式,算式中的数字用大写字母代替。每个字母只能代替一个数字,一个数字也只能被一个字母代替。有多少种数字分配方式可以使得这个算式成立?

解法:爆搜。一共不超过十个字母,把这十个字母列出来然后进行dfs分配数字,分配完后就进行验证是否可以满足式子,还要考虑累加的n-1个数不能是前导0,。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int len[20], n, cnt;
char str[20][20];
bool used[30];
int vis[30];
struct node{
    char ch;
    int num, flag;//flag标记前导0
}a[20];
bool check()
{
    int sum = 0;
    for(int i=1; i<n; i++){
        int t = 0;
        for(int j=0; j<len[i]; j++)
            t = t*10 + vis[str[i][j]-'A'];
        sum += t;
    }
    int ans = 0;
    for(int i=0; i<len[n]; i++)
        ans = ans*10 + vis[str[n][i]-'A'];
    return sum == ans;
}
LL dfs(int pos)
{
    LL ans=0;
    if(pos>=cnt) return check();
    for(int i=0; i<=9; i++){
        if(used[i]==false){
            if(a[pos].flag == 0 && i == 0) continue;
            a[pos].num = i;
            vis[a[pos].ch-'A'] = i;
            used[i] = 1;
            ans += dfs(pos+1);
            used[i] = 0;
        }
    }
    return ans;
}
int main()
{
    while(~scanf("%d", &n))
    {
        cnt = 0;
        memset(vis, 0, sizeof(vis));
        for(int i=1; i<=n; i++){
            scanf("%s", str[i]);
            len[i] = strlen(str[i]);
            for(int j=0; j<len[i]; j++){
                if(!vis[str[i][j]-'A']){
                    a[cnt].flag = 1;
                    a[cnt++].ch = str[i][j], vis[str[i][j]-'A'] = 1;
                }
                if(j==0){
                    for(int k=0; k<cnt; k++){
                        if(a[k].ch == str[i][0]){
                            a[k].flag = 0;
                        }
                    }
                }
            }
        }
        LL ans = 0;
        memset(used,false,sizeof(used));
        ans = dfs(0);
        printf("%lld\n", ans);
    }
    return 0;
}

 B:

题意:计算 1 和 n 两点间最短路的路径和的两倍

解法:计算最短路, 枚举没一条边到两端的距离加上本身长度,判断是等于最短路长度,若是的,那么这条边可以当做最短路的一条边,注意好像spfa会TLE。我是看图猜的题意,

导致很快就写出了这题,以后比赛要注意,猜错容易崩盘。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 10005;
const int maxm = 250000 * 2;
struct EDGE
{
	int to, next, len;
	EDGE() {}
	EDGE(int to, int next, int len) :to(to), next(next), len(len) {}
}edge[maxm];
int head[maxn],edgecnt;
int dis[2][maxn];
int n;
struct node
{
	int u, dis;
	node(int u,int dis):u(u),dis(dis){}
	bool operator < (const node &b) const
	{
		return dis > b.dis;
	}
};
void init()
{
	memset(head, -1, sizeof(head));
	edgecnt = 0;
}
void add(int s, int t, int l)
{
	edge[edgecnt] = EDGE(t, head[s], l);
	head[s] = edgecnt++;
}
void spfa(int st, int dis[])
{
	for (int i = 1; i <= n; i++) dis[i] = INT_MAX;
	dis[st] = 0;
	priority_queue<node> q;
	static bool f[maxn];
	memset(f, 0, sizeof(f));
	q.emplace(st, 0);
	while (!q.empty())
	{
		int u = q.top().u;
		q.pop();
		if (f[u]) continue;
		f[u] = 1;
		for (int i = head[u]; ~i; i = edge[i].next)
		{
			int v = edge[i].to;
			if (dis[v] > dis[u] + edge[i].len)
			{
				dis[v] = dis[u] + edge[i].len;
				q.emplace(v, dis[v]);
			}
		}
	}
}
int main()
{
	int m;
	while (~scanf("%d %d", &n, &m))
	{
		init();
		for (int i = 1; i <= m; i++)
		{
			int s, t, l;
			scanf("%d %d %d", &s, &t, &l);
			s++;
			t++;
			add(s, t, l);
			add(t, s, l);
		}
		spfa(1, dis[0]);
		spfa(n, dis[1]);
		int len = dis[0][n];
		int ans = 0;
		for (int u = 1; u <= n; u++)
		{
			for (int i = head[u]; ~i; i = edge[i].next)
			{
				int v = edge[i].to;
				if (v == u) continue;
				if (dis[0][u] + edge[i].len + dis[1][v] == len)
					ans += edge[i].len;
			}
		}
		printf("%d\n", 2 * ans);
	}
	return 0;
}

 C:

题意:给你N个整数和M个整数,问这M个数中,有几个数可以表达成那N个整数中一个或者两个整数的和。

解法:简单FFT即可。发现我的FFT大概慢100ms,下次要注意。

#include <bits/stdc++.h>
using namespace std;
const double PI = acos(-1);
const int maxn = 800010;
typedef complex <double> Complex;

void rader(Complex *y, int len) {
    for(int i = 1, j = len / 2; i < len - 1; i++) {
        if(i < j) swap(y[i], y[j]);
        int k = len / 2;
        while(j >= k) {j -= k; k /= 2;}
        if(j < k) j += k;
    }
}
void fft(Complex *y, int len, int op) {
    rader(y, len);
    for(int h = 2; h <= len; h <<= 1) {
        double ang = op * 2 * PI / h;
        Complex wn(cos(ang), sin(ang));
        for(int j = 0; j < len; j += h) {
            Complex w(1, 0);
            for(int k = j; k < j + h / 2; k++) {
                Complex u = y[k];
                Complex t = w * y[k + h / 2];
                y[k] = u + t;
                y[k + h / 2] = u - t;
                w = w * wn;
            }
        }
    }
    if(op == -1) for(int i = 0; i < len; i++) y[i] /= len;
}

Complex x1[maxn], x2[maxn];
int n, q, a[maxn];

int sum[maxn];

int main()
{
    while(~scanf("%d", &n))
    {
        memset(a, 0, sizeof(a));
        int len1 = 0;
        for(int i=0; i<n; i++){
            int x;
            scanf("%d", &x);
            a[x]=1;
            len1 = max(len1, x);
        }
        len1++;
        int len=1;
        while(len<len1*2) len<<=1;
        a[0] = 1;
        for(int i=0; i<len1; i++) x1[i] = Complex(a[i], 0);
        for(int i=0; i<len1; i++) x2[i] = Complex(a[i], 0);
        fft(x1, len, 1);
        fft(x2, len, 1);
        for(int i=0; i<len; i++)
            x1[i] = x1[i]*x2[i];
        fft(x1, len, -1);
        for(int i=0; i<len; i++)
            sum[i] = (int)(x1[i].real()+0.5);
        scanf("%d", &q);
        int ans = 0;
        while(q--)
        {
            int x;
            scanf("%d", &x);
            if(sum[x]>0) ans++;
        }
        printf("%d\n", ans);
    }
    return 0;
}

 D:

题意:在一个借书会中,若A喜欢B的书,B喜欢C的书,C喜欢A的书,这样每个人都可以借到书了,输出  yes,若   A喜欢B的书,B喜欢C的书,C喜欢D的书,这样就不能保证每个人都借到书,输出 no

解法:这个可以看做二分匹配,将每一个点拆分为两个点A   B,自己与自己不连边,添加一个源点和一个汇点,源点到A的流的大小为 1   B到汇点的流的大小为 1 ,问是否可以匹配成功让大家都借到书,直接匈牙利也是可以的。一眼想到二分匹配,但是队友因为数据范围说不可能,自己有一点点动摇,然后写个网络流。下次要注意,不能全听队友,要坚持自己。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100100;
const int maxm = 400100;
const int inf = 0x3f3f3f3f;
struct G
{
    int v, cap, next;
    G() {}
    G(int v, int cap, int next) : v(v), cap(cap), next(next) {}
} E[maxm];
int p[maxn], T;
int d[maxn], temp_p[maxn], qw[maxn]; //d顶点到源点的距离标号,temp_p当前狐优化,qw队列
void init()
{
    memset(p, -1, sizeof(p));
    T = 0;
}
void add(int u, int v, int cap)
{
    E[T] = G(v, cap, p[u]);
    p[u] = T++;
    E[T] = G(u, 0, p[v]);
    p[v] = T++;
}
bool bfs(int st, int en, int n)
{
    int i, u, v, head, tail;
    for(i = 0; i <= n; i++) d[i] = -1;
    head = tail = 0;
    d[st] = 0;
    qw[tail] = st;
    while(head <= tail)
    {
        u = qw[head++];
        for(i = p[u]; i + 1; i = E[i].next)
        {
            v = E[i].v;
            if(d[v] == -1 && E[i].cap > 0)
            {
                d[v] = d[u] + 1;
                qw[++tail] = v;
            }
        }
    }
    return (d[en] != -1);
}
int dfs(int u, int en, int f)
{
    if(u == en || f == 0) return f;
    int flow = 0, temp;
    for(; temp_p[u] + 1; temp_p[u] = E[temp_p[u]].next)
    {
        G& e = E[temp_p[u]];
        if(d[u] + 1 == d[e.v])
        {
            temp = dfs(e.v, en, min(f, e.cap));
            if(temp > 0)
            {
                e.cap -= temp;
                E[temp_p[u] ^ 1].cap += temp;
                flow += temp;
                f -= temp;
                if(f == 0)  break;
            }
        }
    }
    return flow;
}
int dinic(int st, int en, int n)
{
    int i, ans = 0;
    while(bfs(st, en, n))
    {
        for(i = 0; i <= n; i++) temp_p[i] = p[i];
        ans += dfs(st, en, inf);
    }
    return ans;
}
int n, m;
int main()
{
    while(~scanf("%d %d", &n,&m)){
        init();
        int st = 2*n;
        int en = st+1;
        for(int i=1; i<=m; i++){
            int u, v;
            scanf("%d %d", &u,&v);
            add(u,v+n,1);
        }
        for(int i=0; i<n; i++) add(st,i,1);
        for(int i=n; i<2*n; i++) add(i,en,1);
        int ans = dinic(st,en,en+1);
        if(ans==n) puts("YES");
        else puts("NO");
    }
    return 0;
}

 E:

题意:有n个机器人(不超过4个),机器人都是要碰到障碍物或者机器人才会停下来的,不然就沿原方向一直走下去,4个机器人都可以移动,求最少移动多少步,机器人1可以到达出口(X)

解法:爆搜,BFS,题目中已经限定了步数,这就是可行性剪枝,难点在于如何表示矩形的状态,我们没有必要把矩形完全表示出来,直接把机器人拿出来即可,把位置拿出来做成一个int的Hash值,然后爆搜即可。队友写这个题,调试时间比较久,需要注意。

#include <bits/stdc++.h>
using namespace std;
int n, h, w, l, ex, ey;
const int dir[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
char g[20][20];
bool vis[100000000];
bool check(int x, int y){
    if(x>=1&&x<=w&&y>=1&&y<=h&&g[x][y]=='.') return true;
    else return false;
}
struct node{
    int step;
    int x[5], y[5];
    int Hash(){
        int ans = 0;
        for(int i=1; i<=n; i++) ans = ans*10 + x[i];
        for(int i=1; i<=n; i++) ans = ans*10 + y[i];
        return ans;
    }
}now;
void BFS()
{
    now.step = 0;
    queue <node >q;
    q.push(now);
    vis[now.Hash()] = 1;
    while(q.size())
    {
        now = q.front();
        q.pop();
        if(now.step>l) continue;
        if(now.x[1]==ex&&now.y[1]==ey){
            printf("%d\n", now.step);
            return;
        }
        node Next;
        for(int i=1; i<=n; i++) g[now.x[i]][now.y[i]] = i+'0';
        for(int i=1; i<=n; i++){
            g[now.x[i]][now.y[i]] = '.';
            for(int j=0; j<4; j++){
                Next = now;
                Next.step++;
                while(check(Next.x[i]+dir[j][0], Next.y[i]+dir[j][1])){
                    Next.x[i]+=dir[j][0];
                    Next.y[i]+=dir[j][1];
                }
                if(!vis[Next.Hash()]){
                    vis[Next.Hash()] = 1;
                    q.push(Next);
                }
            }
            g[now.x[i]][now.y[i]] = i + '0';
        }
        for(int i=1; i<=n; i++) g[now.x[i]][now.y[i]] = '.';//这里一定要改回来,因为x[i]和y[i]已经变化了
    }
    printf("NO SOLUTION\n");
}
int main()
{
    scanf("%d %d %d %d", &n,&h,&w,&l);
    for(int i=1; i<=w; i++){
        scanf("%s", g[i]+1);
        for(int j=1; j<=h; j++){
            if(g[i][j]>='1'&&g[i][j]<='4'){
                now.x[g[i][j]-'0'] = i;
                now.y[g[i][j]-'0'] = j;
                g[i][j] = '.';
            }
            else if(g[i][j] == 'X'){
                ex = i;
                ey = j;
                g[i][j] = '.';
            }
        }
    }
    BFS();
    return 0;
}

 F:

题意:给出一些矩阵,如果矩阵之间有接触算作一个连通分量,问最大的连通分量的面积为多少?

解法:既然接触即算为一个连通分量,那么我们可以分别讨论他的横边接触和竖边接触。将横边和竖边分别存储在不同的结构体数组中,然后对数组进行排序,将互相接触的边对应的矩阵放在统一并查集中。最后统计下所有并查集的面积大小,输出最大的一个即可。

 

#include <bits/stdc++.h>
using namespace std;
const int maxn = 50010;
const int inf = 0x3f3f3f3f;
namespace DSU{
    int fa[maxn];
    void init(){
        for(int i=1; i<maxn; i++) fa[i]=i;
    }
    int find_set(int x){
        if(x==fa[x]) return x;
        else return fa[x] = find_set(fa[x]);
    }
    void union_set(int x, int y){
        x = find_set(x), y = find_set(y);
        if(x!=y){
            fa[x] = y;
        }
    }
}
using namespace DSU;
struct node{
    int x, y, w, h;
}nodes[maxn];
struct line{
    int x,l,r,pos;
    bool operator<(const line &rhs) const{
        return (x<rhs.x||x==rhs.x&&l<rhs.l||x==rhs.x&&l==rhs.l&&r<rhs.r);
    }
}a[maxn*2], b[maxn*2];
//a存水平线段,b存垂直线段
int sum[maxn];
int main()
{
    int n;
    while(~scanf("%d", &n))
    {
        init();
        for(int i=1; i<=n; i++){
            scanf("%d %d %d %d", &nodes[i].x,&nodes[i].y,&nodes[i].w,&nodes[i].h);
            //水平
            a[i].x = nodes[i].y, a[i].l = nodes[i].x, a[i].r = nodes[i].x+nodes[i].w, a[i].pos = i;
            a[i+n].x = nodes[i].y+nodes[i].h, a[i+n].l = nodes[i].x, a[i+n].r = nodes[i].x+nodes[i].w, a[i+n].pos = i;
            //垂直
            b[i].x = nodes[i].x, b[i].l = nodes[i].y, b[i].r = nodes[i].y+nodes[i].h, b[i].pos = i;
            b[i+n].x = nodes[i].x + nodes[i].w, b[i+n].l = nodes[i].y, b[i+n].r = nodes[i].y+nodes[i].h, b[i+n].pos = i;
        }
        sort(a+1, a+2*n+1);
        sort(b+1, b+2*n+1);
        memset(sum, 0, sizeof(sum));
        int m = 2*n;
        //
        for(int i=1,j; i<=m; ){
            int tx = a[i].r;
            j = i+1;
            while(j<=m&&a[j].x==a[i].x&&a[j].l<=tx){
                tx = max(tx, a[j].r);
                union_set(a[i].pos, a[j].pos);
                j++;
            }
            i=j;
        }
        //
        for(int i=1,j; i<=m; ){
            int tx = b[i].r;
            j=i+1;
            while(j<=m&&b[j].x==b[i].x&&b[j].l<=tx){
                tx = max(tx, b[j].r);
                union_set(b[i].pos, b[j].pos);
                j++;
            }
            i=j;
        }
        for(int i=1; i<=n; i++){
            sum[find_set(i)] += nodes[i].h*nodes[i].w;
        }
        int ans = 0;
        for(int i=1; i<=n; i++){
            ans = max(ans, sum[i]);
        }
        printf("%d\n", ans);
    }
    return 0;
}

 G:

题意:给出两个图,通过缩小,问两个图是否是相同的,缩小的时候不是按比例,比如说两行间距为三可以缩小为二,为6可以缩小为5

解法:读这个题的时候我就知道是矩阵离散化了,然后写完离散化丢给队友写暴力旋转4个方向判相等,除了离散化开始写多了点东西,基本没什么问题。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 3010;
int W1, H1, N;
int W2, H2;
int X1[maxn], X2[maxn], Y1[maxn], Y2[maxn];
int X3[maxn], Y3[maxn], X4[maxn], Y4[maxn];
void Rotate()
{
    int ymax = *max_element(Y1, Y1+N);
    for(int i=0; i<N; i++){
        int x = ymax - Y1[i];
        int y = X1[i];
        X1[i] = x;
        Y1[i] = y;
    }
}
bool check()
{
    //第一个离散化后矩形的最左下角的值
    int p1 = 0;
    for(int i=1; i<N; i++){
        if(make_pair(X1[i], Y1[i]) < make_pair(X1[p1], Y1[p1])){
            p1 = i;
        }
    }
    //第一个离散化后矩形的最左下角的值
    int p2 = 0;
    for(int i=1; i<N; i++){
        if(make_pair(X3[i],Y3[i]) < make_pair(X3[p2], Y3[p2])){
            p2 = i;
        }
    }
    for(int i=0; i<N; i++){
        int q1 = (p1+i)%N;
        int q2 = (p2+i)%N;
        if(X1[q1] != X3[q2] || Y1[q1] != Y3[q2]) return false;
    }
    return true;
}

//对x1和x2进行坐标离散化,并且返回离散化后的宽度
int compress(int *x1, int *x2, int w)
{
    vector <int> xs(x2, x2 + N);
    sort(xs.begin(), xs.end());
    xs.erase(unique(xs.begin(), xs.end()), xs.end());
    for(int i = 0; i < N; i++)
    {
        x1[i] = lower_bound(xs.begin(), xs.end(), x1[i]) - xs.begin();
        x2[i] = lower_bound(xs.begin(), xs.end(), x2[i]) - xs.begin();
    }
    return xs.size();
}

int main()
{
    while(~scanf("%d", &N))
    {
        //ZXY
        W1 = 0;
        H1 = 0;
        for(int i = 0; i < N; i++)
        {
            scanf("%d %d", &X1[i], &Y1[i]);
            X2[i] = X1[i], Y2[i] = Y1[i];
            W1 = max(W1, X1[i]);
            H1 = max(H1, Y1[i]);
        }
        W1 = compress(X1, X2, W1);
        H1 = compress(Y1, Y2, H1);
        W2 = 0;
        H2 = 0;
        scanf("%d", &N);
        for(int i = 0; i < N; i++)
        {
            scanf("%d %d", &X3[i], &Y3[i]);
            X4[i] = X3[i], Y4[i] = Y3[i];
            W2 = max(W2, X3[i]);
            H2 = max(H2, Y3[i]);
        }
        W2 = compress(X3, X4, W2);
        H2 = compress(Y3, Y4, H2);
        //LYY
        if(check())
        {
            puts("yes");
            continue;
        }
        Rotate();
        if(check())
        {
            puts("yes");
            continue;
        }
        Rotate();
        if(check())
        {
            puts("yes");
            continue;
        }
        Rotate();
        if(check())
        {
            puts("yes");
            continue;
        }
        puts("no");
    }
    return 0;
}

 H: 留坑

I:给了一些数字和字符,字符里面有问号,这个序列是个圆形,我们可以从任意一个数字开始重新启动一个序列,现在序列里面每个?可以替换成+,-,*任意一个,且优先级随便考虑,现在问这n次移动构成的n个序列的最小值和最大值是多少,输出每一轮的最小最大的绝对值,拼成一个字符串,最后输出一个空行。n<=200。

解法:把字符串copy一份,变成长度400的字符串,对这个序列做一个区间DP即可。转移很简单,看代码吧。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxn = 405;
LL mx[maxn][maxn];
LL mi[maxn][maxn];
void getMaxMin(const vector<int> &num, const vector<char> &symbol)
{
    memset(mx, 0x80, sizeof(mx));
    memset(mi, 0x7F, sizeof(mi));
    int n = num.size();
    for(int i = 0; i < n; i++)
    {
        mi[i][i] = mx[i][i] = num[i];
    }
    for(int len = 2; len <= n / 2; len++)
    {
        for(int st = 0; st + len <= n; st++)
        {
            int en = st + len - 1;
            for(int mid = st; mid < en; mid++)
            {
                if(symbol[mid] == '+' || symbol[mid] == '?')
                {
                    mi[st][en] = min(mi[st][en], mi[st][mid] + mi[mid + 1][en]);
                    mx[st][en] = max(mx[st][en], mx[st][mid] + mx[mid + 1][en]);
                }
                if(symbol[mid] == '-' || symbol[mid] == '?')
                {
                    mi[st][en] = min(mi[st][en], mi[st][mid] - mx[mid + 1][en]);
                    mx[st][en] = max(mx[st][en], mx[st][mid] - mi[mid + 1][en]);
                }
                if(symbol[mid] == '*' || symbol[mid] == '?')
                {
                    mi[st][en] = min(mi[st][en], mi[st][mid] * mi[mid + 1][en]);
                    mi[st][en] = min(mi[st][en], mi[st][mid] * mx[mid + 1][en]);
                    mi[st][en] = min(mi[st][en], mx[st][mid] * mi[mid + 1][en]);
                    mi[st][en] = min(mi[st][en], mx[st][mid] * mx[mid + 1][en]);
                    mx[st][en] = max(mx[st][en], mx[st][mid] * mx[mid + 1][en]);
                    mx[st][en] = max(mx[st][en], mx[st][mid] * mi[mid + 1][en]);
                    mx[st][en] = max(mx[st][en], mi[st][mid] * mx[mid + 1][en]);
                    mx[st][en] = max(mx[st][en], mi[st][mid] * mi[mid + 1][en]);
                }
            }
        }
    }
}
int main()
{
    int n;
    while(~scanf("%d", &n))
    {
        vector<int> num;
        vector<char> symbol;
        for(int i = 0; i < n; i++)
        {
            int x;
            scanf("%d", &x);
            num.push_back(x);
            char s[10];
            scanf("%s", s);
            symbol.push_back(s[0]);
        }
        for(int i = 0; i < n; i++)
        {
            num.push_back(num[i]);
            symbol.push_back(symbol[i]);
        }
        getMaxMin(num, symbol);
        for(int i = 0; i < n; i++)
        {
            printf("%lld%lld", abs(mi[i][i + n - 1]), abs(mx[i][i + n - 1]));
        }
        printf("\n");
    }
    return 0;
}

 J:

题意:给一个小矩形,再给一个大矩形,问小矩形在大矩形出现的次数。

解法:矩阵Hash。双值Hash,模数取成121和131即可过。

#include <bits/stdc++.h>
using namespace std;
const unsigned int BASE1 = 121;
const unsigned int BASE2 = 131;
const int mod = 99999997;
const int maxn = 2010;
int n, m, a, b, q;
unsigned int hash1[maxn][maxn], hash2[maxn][maxn];
unsigned int bas1[maxn], bas2[maxn];
unsigned int getHash()
{
    for (int i = 1; i <= a; i++)
        for (int j = 1; j <= b; j++)
            hash2[i][j] += hash2[i - 1][j] * BASE1;
    for (int i = 1; i <= a; i++)
    {
        for (int j = 1; j <= b; j++)
        {
            hash2[i][j] += hash2[i][j - 1] * BASE2;
        }
    }
    return hash2[a][b];
}
char str1[maxn];

int  main()
{
    while (~scanf("%d %d %d %d", &a, &b, &n, &m))
    {
        for (int i = 1; i <= a; i++)
        {
            scanf("%s", str1+1);
            for (int j = 1; j <= b; j++)
            {
                if (str1[j] == 'o')
                {
                    hash2[i][j] = 1;
                }
                else
                {
                    hash2[i][j] = 0;
                }
            }
        }
        unsigned int des = getHash();
        bas1[0] = bas2[0] = 1;
        for (int i = 1; i <= 1010; i++) bas1[i] = bas1[i - 1] * BASE1, bas2[i] = bas2[i - 1] * BASE2;
        for (int i = 1; i <= n; i++)
        {
            scanf("%s", str1+1);
            for (int j = 1; j <= m; j++)
            {
                if (str1[j] == 'o')
                {
                    hash1[i][j] = 1;
                }
                else
                {
                    hash1[i][j] = 0;
                }
            }
        }
        int ans = 0;
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= m; j++)
            {
                hash1[i][j] += hash1[i - 1][j] * BASE1;
            }
        }
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= m; j++)
            {
                hash1[i][j] += hash1[i][j - 1] * BASE2;
            }
        }
        for(int i=a; i<=n; i++){
            for(int j=b; j<=m; j++){
                unsigned int h = hash1[i][j];
                h -= hash1[i-a][j]*bas1[a];
                h -= hash1[i][j-b]*bas2[b];
                h += hash1[i-a][j-b]*bas1[a]*bas2[b];
                if(h==des){
                    ans++;
                }
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

 

posted @ 2017-09-08 14:01  zxycoder  阅读(292)  评论(0编辑  收藏  举报