Wannafly模拟赛

题目描述

给出一个n * m的矩阵。让你从中发现一个最大的正方形。使得这样子的正方形在矩阵中出现了至少两次。输出最大正方形的边长。

输入描述:

第一行两个整数n, m代表矩阵的长和宽;
接下来n行,每行m个字符(小写字母),表示矩阵;

输出描述:

输出一个整数表示满足条件的最大正方形的边长。
示例1

输入

5 10
ljkfghdfas
isdfjksiye
pgljkijlgp
eyisdafdsi
lnpglkfkjl

输出

3

备注:

对于30%的数据,n,m≤100;
对于100%的数据,n,m≤500;



数据还是挺好的,不二分超时,用set超内存。得必须自己写字符串二维hash;

此题是原题,URAL

分析:他一定是满足二分性质的~~~

二维字符串hash,没听说过,其实和子矩阵和类似,就是用了一种数学方法,可以通过相加减得到一个子矩阵的hash值。

先一行一行hash,然后是列,组合起来。

逻辑还是很好写的,可以当做一个小板子。

#include <bits/stdc++.h>

using namespace std;

typedef unsigned long long ull;
const int N = 500 + 10,INF = 0x3f3f3f3f;
const int seed = 131,Seed = 1789;

char ori[N][N];
ull hash1[N][N],seed_pow[N];    ///row
ull hash2[N][N],Seed_pow[N];    ///col
ull a[N*N];
int n,m;


bool check(int k) {
    int tot = 0;

    for(int i = k; i <= n; i++)
    {
        for(int j = k ; j <= m; j++)
        {
            ull tmp = hash2[i][j] - hash2[i-k][j]*Seed_pow[k] - hash2[i][j-k]*seed_pow[k] + hash2[i-k][j-k]*Seed_pow[k]*seed_pow[k];
            a[++tot] = tmp;
        }
    }

    sort(a+1,a+1+tot);
    for(int i = 1; i <= tot - 1; i++)
        if(a[i]==a[i+1]) return true;
    return false;

}

int main()
{
    freopen("in.txt","r",stdin);
    seed_pow[0] = Seed_pow[0] = 1;
    for(int i = 1; i < N; i++)
    {
        seed_pow[i] = seed_pow[i-1]*seed;
        Seed_pow[i] = Seed_pow[i-1]*Seed;
    }

    scanf("%d%d",&n,&m);

    for(int i = 1; i <= n; i++) scanf("%s",ori[i]+1);

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            hash1[i][j] = hash1[i][j-1]*seed + ori[i][j];

    for(int i = 1; i <= m; i++)
        for(int j = 1; j <= n; j++)
            hash2[j][i] = hash2[j-1][i]*Seed + hash1[j][i];

    int ans = 0;
    int l = 0,r = min(n,m);

    while(l<=r) {
        int mid = (l + r) >> 1;
        if(check(mid)) ans = mid,l = mid + 1;
        else r = mid - 1;
    }
    printf("%d
",ans);


    return 0;
}
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

shy有一颗树,树有n个结点。有k种不同颜色的染料给树染色。一个染色方案是合法的,当且仅当对于所有相同颜色的点对(x,y),x到y的路径上的所有点的颜色都要与x和y相同。请统计方案数。

输入描述:

第一行两个整数n,k代表点数和颜色数;
接下来n-1行,每行两个整数x,y表示x与y之间存在一条边;

输出描述:

输出一个整数表示方案数(mod 1e9+7)。
示例1

输入

4 3
1 2
2 3
2 4

输出

39

备注:

对于30%的数据,n≤10, k≤3;
对于100%的数据,n,k≤300。

 顿时对牛客上的题目好感+1。

此题看上去是一个染色,其实任意两个相同颜色的点对,之间都的一个颜色,那就是一个联通分量全是一个颜色。

树,就可以看做是一个点集合,挑哪些点染同一种颜色。显然是DP做法。

d[i][j] :前 i 个点,染 j 种颜色的方案数。

d[i][j] = d[i-1][j] + d[i-1][j-1]*(k+1-j);

#include <bits/stdc++.h>

using namespace std;

const int mod = 1e9+7;

long long d[305][305];

int main()
{
    int n,k;
    scanf("%d%d",&n,&k);

    for(int i = 0; i < n-1; i++) {
        int x,y;
        scanf("%d%d",&x,&y);
    }

    memset(d,0,sizeof(d));
    d[0][0] = 1;

    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= k; j++) {
            d[i][j] = (d[i-1][j] + d[i-1][j-1]*(k+1-j))%mod;
        }
    }

    long long ans = 0;
    for(int j = 1; j <= k; j++)
        ans = (ans + d[n][j])%mod;
    cout<<ans<<endl;


    return 0;
}
原文地址:https://www.cnblogs.com/TreeDream/p/7846372.html