题目描述
给出一个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
空间限制: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; }