目前对我来说比较难的题
由于这类题对现在的我来说比较吃力,所以我不太可能完全弄懂这道题为什么会这样想到,以及为什么会往这个方向做,所以我只会写出这道题的解决思路,和代码上的实现难点,可能还有一些我最开始砍到这道题的第一眼的思路。
1.https://ac.nowcoder.com/acm/contest/129231/F
这道题的思路区别于枚举每个分割方案,是枚举中间的每个子回文子串,计算出这段回文子串的贡献,也就是这段子串的左边的分割方案和右边的分割方案相乘,再×这个回文子串的价值,这样就可以把每个回文子串的总贡献加起来,得到所有分割方案的总价值。代码上的实现:
首先我们需要对所有的子串是不是回文的进行标记,我们可以观察到每个字符单独分割是一个回文子串,所以我们设置一个二维数组pal,x代表这个子串的起点,y代表截至的终点,所以对于每个pal的起始点都是自己的子串我们都需要设置成真,然后我们做进一步的初始化,也就是连续两个相邻的相同的字符组成的子串一定是回文的,那么我们的初始化的代码,就是`vector<vector
for(int i=1;i<=n;i++){
pal[i][i]=true;
if(i<n&&s[i+1]==s[i])
pal[i][i+1]=true;
} 然后我们如何判断左端点l,右端点r的字符串是不是回文的,只需要看左端点l+1,右端点r-1的字符串是不是回文的,所以代码如下for(int len=3;len<=n;len++){
for(int l=1;l+len-1<=n;l++){
int r=l+len-1;
if(s[r]==s[l]&&pal[l+1][r-1])
pal[l][r]=true;
}
} 这步完了之后我们已经可以通过pal[i][j]来判断i到j的字符串是不是回文的字符串了,那么下一步就是如何计算1到i-1的字符串的分割方案,和l+1到n的分割方案。首先先给出代码吧vector
f[0]=1;///代表字符串第一个到第i个的字符串可以的分割方案
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
if(pal[j][i]){
f[i]=(f[i]+f[j-1])%mod;
}
}
}
vector
g[n+1]=1;
for(int i=n;i>=1;i--){
for(int j=i;j<=n;j++){
if(pal[i][j]){
g[i]=(g[j+1]+g[i])%mod;
}
}
}`
这里面有些我还没怎么弄到彻底明白的问题。一个是为什么f和g的初始化需要弄到f[0]和g[n+1]解释说是因为不分割也是一种方案,所以把他们弄到两边去,然后f和g的dp上的实现是需要用到j-1,j+1的,也就是说如果我只设置f1=1,那么在i=1的时候,j=1,那么我们的f1加的f0是没有定义的,那么我们就需要在此基础上进行特殊判断,同理g也需要进行大量的特殊判断,而我们把f和g设置成0和n+1就不需要这么多的特殊判断。还有就是下一次再遇到类似的题我应该如何想到构建这个dp数组,已经如何想到使用dp来记录方案数,这道题其实最开始我根本想不到和dp是有关的
到这里我觉得最难得两个部分都已经解决了,剩下得就是计算每个回文子串得贡献,然后加起来,记得取模
2.https://pintia.cn/problem-sets/2033815669795565568/exam/problems/type/7?problemSetProblemId=2033815669829120010
这道题应该算是一个模板题,但是之前学关于树的很少,所以对于现在的我来说比较难。
这道题需要我们做两个事情,一个是根据给出的中序和后序重建出完整的二叉树;第二个是由完整的二叉树求出这棵树的右视图和左视图,实现分别是通过类似前序遍历的方法来实现。
代码如下:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=1e6;
int a[N];//中序
int b[N];//后序
vector<int>g[N];
int dfs_rebuild(int l1,int r1,int l2,int r2){
if(l1>r1||l2>r2)
return -1;
int rt=b[r2];
int R;
for(int i=l1;i<=r1;i++){
if(a[i]==rt){
R=i-1;
break;
}
}
int l=dfs_rebuild(l1,R,l2,l2+(R-l1));
int r=dfs_rebuild(R+2,r1,l2+(R-l1)+1,r2-1);
if(l!=-1)g[rt].push_back(l);
if(r!=-1)g[rt].push_back(r);
return rt;
}
int mx=0;
void dfs_r(int node,int depth){
a[depth]=node;
mx=max(mx,depth);
for(auto&u:g[node]){
dfs_r(u,depth+1);
}
}
void dfs_l(int node,int depth){
a[depth]=node;
mx=max(mx,depth);
for(int i=int(g[node].size())-1;i>=0;i--){
dfs_l(g[node][i],depth+1);
}
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
int rt=dfs_rebuild(1,n,1,n);
dfs_r(rt,1);
cout<<"R: ";
for(int i=1;i<=mx;i++){
cout<<a[i]<<" \n"[i==mx];
}
dfs_l(rt,1);
cout<<"L: ";
for(int i=1;i<=mx;i++){
cout<<a[i]<<" \n"[i==mx];
}
}
3.Not Equal
https://ac.nowcoder.com/acm/contest/129582/E
虽然这道题我在比赛的时候并没有做,所以对于这道题的第一思路很少,赛后补题我也是跟着AI一步一步理解来补出来的。所以能将的很少,而且大概已经在题解里面写了,就不再赘述
题解链接https://www.cnblogs.com/wtpavssite/p/19735817
4.小红的点构造
来源:原题链接
这道题是我赛后补题跟着题解用AI做的,大概能理解里面每一步是在做什么,但是不确定下一次会不会写
代码:
里面的注释是我根据自己的理解写的
点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
#define PII pair<int,int>
#define pb push_back
#define fi first
#define se second
void solve() {
int n, k;
cin >> n >> k;
vector<PII> P;///存进去的曼哈顿距离是1的点位
vector<ll> E;///这个的back表示现在有多少个距离1
P.pb({0, 0});///最开始从这个点开始存
E.pb(0);
int d = 1;///正方形的边长
while (P.size() < n) {
///先找上面的点(不包含角上)
for (int x = 0; x < d && P.size() < n; ++x) {
P.pb({x, d});
E.pb(E.back() + (x == 0 ? 1 : 2));///除了原点正上方的那个点,其他的点都会和两个其他的点形成曼哈顿距离为1的距离,而相邻对就会+2
}
///找右边的点(不包含顶点)
for (int y = 0; y < d && P.size() < n; ++y) {
P.pb({d, y});
E.pb(E.back() + (y == 0 ? 1 : 2));
}
///如果当前边长两边的点都进去了还是不够就加上顶点
if (P.size() < n) {
P.pb({d, d});
E.pb(E.back() + 2);///顶点也是会形成距离2
}
d++;
}
if (E.back() < k) {///如果所有点总的距离也就是相邻对都不满足要求
cout << "No" << endl;
return;
}
cout << "Yes" << endl;
int pos = 0;
for (int i = 0; i < n; ++i) {
if (E[i] <= k) {
pos = i + 1;///pos找到第一个输出了的相邻对大于要求的位置
}
}
for (int i = 0; i < pos; ++i) {
cout << P[i].fi << " " << P[i].se << endl;
}
int r = k - E[pos - 1], rem = n - pos;
///r代表还剩下多少相邻的没有输出
///rem代表n里面还有多少对
if (rem) {
if (r == 1) {///由于E每次加上去都是1或者2,所以r只有0或1的情况
int mx = -1, yy = -1;
for (int i = 0; i < pos; ++i) {///找到现在x坐标最大的一个点,在他的右边加上一个点,刚好使相邻对加1
if (P[i].fi > mx) {
mx = P[i].fi;
yy = P[i].se;
}
}
cout << mx + 1 << " " << yy << endl;
rem--;
}
int x = -1e8, y = -1e8;
while (rem > 0) {///输出剩下的点位,让他们不相邻
cout << x << " " << y << endl;
x += 2;
rem--;
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
t=1;
// cin>>t;
while(t--){
solve();
}
}
浙公网安备 33010602011771号