• 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
    ", 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
    ", 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
    ", 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
    ", 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
    ");
    }
    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
    ", 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("
    ");
        }
        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
    ", ans);
        }
        return 0;
    }
    
  • 相关阅读:
    Edit Distance编辑距离(NM tag)- sam/bam格式解读进阶
    《开讲啦》 20160910 颜宁:女科学家去哪儿了?
    pysam
    Python项目实战
    最小二乘估计法
    最大似然估计(Maximum Likelihood,ML)
    HMM隐马尔科夫模型
    贝叶斯推断|朴素贝叶斯分类|贝叶斯定理
    解决“tar:Exiting with failure status due to previous errors”【转】
    df -h执行卡住不动问题解决【转】
  • 原文地址:https://www.cnblogs.com/spfa/p/7494308.html
Copyright © 2020-2023  润新知