牛客小白月赛47
比赛链接
牛客小白月赛47
D.造桥
题目描述
今天是愉快的周末,牛可乐和牛妹在一起玩游戏。牛妹给了牛可乐 \(n\) 个造桥的零件,每个零件以字符串的形式给出,每个字符串两端的字符是零件的接口,两个零件可以通过连接不同端的接口(一个零件的左端只能连接另一个零件的右端,右端则只能连接左端)得到一个更长的零件,新零件的长度是原零件的长度之和。
牛妹规定,零件不能翻转,且零件左边的接口只能由该零件左边的零件去连接(这意味着,应该按顺序选取零件),右端同理。
牛可乐想得到牛妹的赞许,因此他要想用牛妹给的零件拼接一个尽可能长的桥梁,你能帮帮他吗?
输入描述:
第一行一个整数 \(T\), 代表案例数。
对于每一个样例: 第一行一个数 \(n\), 表示字符串的个数。
接下来有 \(n\) 行, 每行一个字符串, 每个字符串的长度 \(\geqslant 2\) 。
\(0
所有案例的字符串长度的和不超过 \(2 e 5\) 。
保证所有字符均为小写字符。
输出描述:
\(n\) 个字符串能拼接的最大字符串长度。
示例1
输入
1
6
ab
baabc
bb
ba
ba
ad
输出
8
说明
按顺序依次拼接:\(1,3,5,6\)号字符串。
解题思路
思维,dp
相当于将每个字符串的第一个字符向最后一个字符连边,权值为字符串长度,从左到右求最大权值之和
-
状态表示:\(f[i]\) 表示以 \(i\) 结尾的最大权值
-
状态计算:\(f[r]=max(f[r],(int)s.size()+f[l])\),其中 \(l,r\) 分别为字符串 \(s\) 的前后字符
分析:当前字符串是否对于 \(r\) 结尾的最大权值之和有贡献
代码
// %%%Skyqwq
#include
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair PII;
typedef pair PLL;
template bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=27;
int f[N],t,n;
int main()
{
for(cin>>t;t;t--)
{
memset(f,0,sizeof f);
cin>>n;
for(int i=1;i<=n;i++)
{
string s;
cin>>s;
f[s.back()-'a']=max(f[s.back()-'a'],(int)s.size()+f[s[0]-'a']);
}
int res=0;
for(int i=0;i<26;i++)res=max(res,f[i]);
cout<
E.牛牛的方格图
题目描述
牛牛: “你喜欢玩数独吗? 。
牛牛有一个 \(n * m\) 的方格图,每个格子都有自己的颜色,第 \(i\) 行第 \(j\) 列格子上的颜色记为 \(\operatorname{col}(i, j)\) 。
对于任意两个不同位置的颜色相同的点,我们认为其覆盖了一个以它们为对角线上顶点的矩形中的所有点。
严格来说,一个点 \(P\left(i_{p}, j_{p}\right)\) 被覆盖,当且仅当存在两个点 \(A\left(i_{a}, j_{a}\right)\) 和 \(B\left(i_{b}, j_{b}\right)\) 使得以下四个条件都成立:
1: \(\operatorname{col}\left(i_{a}, j_{a}\right)=\operatorname{col}\left(i_{b}, j_{b}\right)\)
2: \(i_{a} \neq i_{b} \| j_{a} \neq j_{b}\)
3: \(\min \left(i_{a}, i_{b}\right) \leqslant i_{p} \leqslant \max \left(i_{a}, i_{b}\right)\)
4: \(\min \left(j_{a}, j_{b}\right) \leqslant j_{p} \leqslant \max \left(j_{a}, j_{b}\right)\)
现在牛牛想知道这张方格图中有多少个顶点尚末被覆盖。
输入描述:
第一行输入两个数 \(n, m\) 代表方格图的行数和列数。
接下来 \(n\) 行每行 \(m\) 个数描述了方格图中每个格子上的颜色。
\(0
输出描述:
输出一行一个整数代表答案。
示例1
输入
3 4
1 3 3 4
2 3 1 4
6 3 3 4
输出
1
说明
6所在方格未被覆盖。
解题思路
思维,二维前缀和
先将同一个颜色的位置提取出来,如果一个颜色出现的位置大于等于 \(2\),则求出覆盖所有点的最小矩形,即找出最大和最小的横纵坐标,设定一个数组 \(ne[i][j]\),表示位于 \((i,j)\) 连续覆盖的最左边的纵坐标,每次标记时可利用此数组快速标记未标记的位置,当然,也可以利用二维前缀和做标记
- 时间复杂度:\(O(100000+nm)\)
代码
// Problem: 牛牛的方格图
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/11224/E
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair PII;
typedef pair PLL;
template bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=1e6+6,M=1005;
int n,m,x,ne[M][M];
vector c[N];
bool v[M][M];
int main()
{
read(n),read(m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)read(x),c[x].pb({i,j});
}
for(int i=0;i<=1e6;i++)
{
if(c[i].size()>1)
{
int x1=M,y1=M,x2=0,y2=0;
for(auto t:c[i])
{
x1=min(x1,t.fi);
y1=min(y1,t.se);
x2=max(x2,t.fi);
y2=max(y2,t.se);
}
for(int j=x1;j<=x2;j++)
for(int k=y1;k<=y2;k++)
{
if(v[j][k])k=ne[j][k];
else
{
ne[j][k]=y2;
v[j][k]=1;
}
}
}
}
int res=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)res+=!v[i][j];
printf("%d",res);
return 0;
}
- 前缀和
// Problem: 牛牛的方格图
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/11224/E
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair PII;
typedef pair PLL;
template bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=1e6+6,M=1005;
int n,m,x,s[M][M];
vector c[N];
bool v[M][M];
int main()
{
read(n),read(m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)read(x),c[x].pb({i,j});
}
for(int i=0;i<=1e6;i++)
{
if(c[i].size()>1)
{
int x1=M,y1=M,x2=0,y2=0;
for(auto t:c[i])
{
x1=min(x1,t.fi);
y1=min(y1,t.se);
x2=max(x2,t.fi);
y2=max(y2,t.se);
}
s[x1][y1]++;
s[x1][y2+1]--;
s[x2+1][y1]--;
s[x2+1][y2+1]++;
}
}
int res=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)s[i][j]+=s[i][j-1]+s[i-1][j]-s[i-1][j-1],res+=!s[i][j];
printf("%d",res);
return 0;
}