1、P1028魔族密碼 :https://vijos.org/p/1028
分析:最長不下降子序列的變形, 把數字類比成前綴問題
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn=2005;
string word[maxn];
int a[maxn],s[maxn];
bool cmp(int i,int j) //比較是否爲前綴
{
int len=word[j].size();
for (int k=0;k<len;k++)
if (word[j][k] != word[i][k]) return false;
return true;
}
int main()
{
int n;
scanf("%d",&n);
for (int i=0;i<n;i++)
{
cin>>word[i];
s[i]=word[i].size();
}
a[0]=1;
for (int i=1;i<n;i++) //LIS模板
{
for (int j=0;j<i;j++)
{
if (cmp(i,j))
a[i]=max(a[i],a[j]);
}
a[i]++;
}
int ans=0;
for (int i=0;i<n;i++)
ans=max(a[i],ans);
printf("%d",ans);
return 0;
}
#include <cstdio>
#include <iostream>
using namespace std;
const int maxn=1005;
int main()
{
int f1[maxn],f2[maxn],a[maxn];
int n;
scanf("%d",&n);
for (int i=0;i<n;i++)
scanf("%d",&a[i]);
for (int i=0;i<n;i++)
{
f1[i]=1;
f2[i]=1;
}
for (int i=1;i<n;i++)
for (int j=0;j<i;j++)
if (a[i]>a[j]) f1[i]=max(f1[i],f1[j]+1);
for (int i=n-2;i>=0;i--)
for (int j=n-1;j>i;j--)
if (a[i]>a[j]) f2[i]=max(f2[i],f2[j]+1);
int sum=0;
for (int i=0;i<n;i++)
sum=max(sum,f2[i]+f1[i]-1); //每個數被重複計數一次,應-1
sum=n-sum;
printf("%d",sum);
return 0;
}
第二次:以第K項爲開始(一定要包含第K項)的最長LIS)
注意的地方:要用長整型,二分查找的修改由temp>=dp[mid].num修改爲temp>dp[mid].num
因爲例如數據 14 3
0 0 0 6 8 4 5 6 7 9 8 9 5 10
注意觀察前三項在DP時的變化。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=300005;
struct Node
{
long long num;
};
Node dp[maxn];
int main()
{
int n,k,len=0;
long long tmp;
scanf("%d%d",&n,&k);
dp[0].num=-1;
int top=0;
for (int i=1;i<=k;i++)
{
scanf("%lld",&tmp);
if (tmp > dp[top].num)
{
dp[++top].num=tmp;
if (i == k)
{
len=top;
}
}
else
{
int l=1,r=top;
int mid;
while (l <= r)
{
mid=(l+r)/2;
if (tmp > dp[mid].num){
l=mid+1;
}
else{
r=mid-1;
}
}
dp[l].num=tmp;
if (i == k)
len=l;
}
}
top=1;
dp[top].num=tmp;
for (int i=k+1;i<=n;i++)
{
scanf("%lld",&tmp);
if (tmp>dp[top].num){
dp[++top].num=tmp;
}
else
{
int l=1,r=top;
int mid;
while (l <= r)
{
mid=(l+r)/2;
if (tmp > dp[mid].num){
l=mid+1;
}
else{
r=mid-1;
}
}
if (l!=1)
{
dp[l].num=tmp;
}
}
}
printf("%d\n",top+len-1);
return 0;
}
//v=(|x1-x2|+|y1-y2|)^2
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
struct node
{
int x,y,score;
};
int poww(node a,node b)
{
return (abs(a.x-b.x)+abs(a.y-b.y))*(abs(a.x-b.x)+abs(a.y-b.y));
}
node sum[2501];
int main()
{
int n,a;
scanf("%d",&n);
for (int i=0;i<n;i++)
for (int j=0;j<n;j++){
scanf("%d",&a);
sum[a].x=i;
sum[a].y=j;
}
for (int i=n*n-1;i>=1;i--) // 逆序LIS
for (int j=i+1;j<=n*n;j++)
{
int p=poww(sum[i],sum[j]);
sum[i].score=max(sum[j].score+p,sum[i].score);
}
printf("%d\n",sum[1].score);
return 0;
}
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=10005;
int a[maxn],f[maxn];
int main()
{
int n;
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
for (int i=1;i<=n;i++)
for (int j=i+1;j<=n;j++)
{
if (f[i]%2==1){ //奇數情況
if (a[j]>a[i]) f[j]=max(f[j],f[i]+1);
}
else if(f[i]%2==0) //偶數情況
if (a[j]<a[i]) f[j]=max(f[j],f[i]+1);
}
int ans=0;
for (int i=1;i<=n;i++)
ans=max(ans,f[i]);
cout<<ans+1<<endl;
return 0;
}
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=505;
//// dp[i][j] 表示 第一串前i個, 第二串前j個 並且以b[j]結尾 的最大公共子序列
int a[maxn],b[maxn];
int dp[maxn][maxn];
int main()
{
int t;
scanf("%d",&t);
while (t--)
{
int n,m;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
scanf("%d",&m);
for (int i=0;i<m;i++)
scanf("%d",&b[i]);
memset(dp,0,sizeof(dp));
for (int i=0;i<n;i++)
{
int _max=0;
for (int j=0;j<m;j++)
{
dp[i+1][j+1]=dp[i][j+1];
if (a[i] > b[j])
{
_max=max(_max,dp[i][j+1]);
}
if (a[i] == b[j]) dp[i+1][j+1]=_max+1;
}
}
int ans=0;
for (int i=1;i<=m;i++)
ans=max(ans,dp[n][i]);
printf("%d\n",ans);
}
return 0;
}