記事ディレクトリ
- 最長のジグザグ サブシーケンス
- 最小面積部分行列
1. 最長の ZigZag サブシーケンスIO リンク
この質問のアイデア:この質問は dp 問題です。集合の除算: a[i] が 1 つだけであるか、最後から 2 番目の要素が j 番目の数値であり、a[j]:g[ を取得するには降順する必要があります。 j]+1、状態計算は f[i]=max(f[i],g[j]+1) です。これが最初のケースで、もう 1 つは a[i] が 1 つだけ存在する場合、または最後から 2 番目の要素は j 番目の数値であり、増加する必要があります a[j]:f[j] + 1 状態の計算 g[i]=max(g[i],f[j]+1) を取得します。条件を満たす 2 番目の条件 この場合、各状態の最長は、 res=max(f[i],g[i]) 内の最長のサブシーケンスになります。
#include <bits/stdc++.h>
constexpr int N=55;
//集合划分:【只有一个a[i]】【其他:倒数第二个元素是第j个数字并且需要是下降得到a[j]:g[j] + 1】
//状态计算:f[i] = max(f[i], g[j] + 1);
int n;
int a[N];
int f[N];//表示以第i个数字结尾并且是前一个数字上升得到的a[i]
int g[N];//表示以第i个数字结尾并且是前一个数字下降得到的a[i]
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);std::cout.tie(nullptr);
std::cin>>n;
for(int i=1;i<=n;i++) std::cin>>a[i];
int res=0;
for(int i = 1; i <=n; i ++ ){
f[i] = g[i] = 1;
for(int j = 1; j < i; j ++ ){
if(a[i] > a[j]) f[i] = std::max(g[j] + 1, f[i]);
else if(a[i] < a[j])
g[i] = std::max(f[j] + 1 , g[i]);
}
res = std::max(res, std::max(f[i], g[i]));
}
std::cout<<res<<std::endl;
return 0;
}
2. 最小面積サブマトリクスIO リンク
この質問のアイデア:この質問では、プレフィックス合計とダブル ポインター メソッドを使用できます。暴力は、知識の複雑さが比較的高い問題を解決するためにも使用できます。各列で 1 次元のプレフィックス合計演算を実行します。次に、最初に上位とダブル ポインターを列挙します。要件としては、要素が最も少ない部分行列(右の境界を固定すると、右に行くほど左の境界の和が小さくなり、面積も小さくなる)が挙げられます。
#include <bits/stdc++.h>
constexpr int N=110;
#define INF 0x3f3f3f3f
int n,m,k;
int g[N][N];
int ans=INF;
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);std::cout.tie(nullptr);
std::cin>>n>>m>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
std::cin>>g[i][j];
g[i][j]+=g[i-1][j];
}
for(int x=1;x<=n;x++)//处理上下边界
for(int y=x;y<=n;y++)
for(int l=1,r=1,sum=0;r<=m;r++){//对边界中的矩阵进行枚举
sum+=g[y][r]-g[x-1][r];
while(sum-g[y][l]+g[x-1][l]>=k)
{
sum-=g[y][l]-g[x-1][l];
l++;
}
if(sum>=k) ans=std::min(ans,(y-x+1)*(r-l+1));
}
if(ans==INF) std::cout<<-1<<std::endl;
else std::cout<<ans<<std::endl;
return 0;
}