1.多重背包
void zoreonepack(int val,int cost)
{
for(int i=v;i>=cost;i--)
{
if(dp[i-cost]+val>dp[i])
{
dp[i]=dp[i-cost]+val;
}
}
}
void completepack(int val,int cost)
{
for(int i=cost;i<=v;i++)
{
dp[i]=max(dp[i],dp[i-cost]+val);
}
}
void multipack(int val,int cost,int num)
{
if(num*cost>=v)
{
completepack(val,cost);
}
else
{
int k=1;
while(k<num)
{
zoreonepack(k*val,k*cost);
num-=k;k+=k;
}
zoreonepack(num*val,num*cost);
}
}
2.O(n^2)TSP
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define INF 0x3f3f3f3f
int n,d[1005],dp[1005][1005];
int dis(int a,int b)
{
int tmp=abs(d[a]-d[b]);
return min(tmp,360-tmp);
}
int TSP_Dp()
{
dp[2][1]=dis(1,2);
for (int i = 3; i <= n + 1; i++) {
dp[i][i-1] = INF;
for (int j = 1; j < i-1; j++) {
dp[i][i-1] = min(dp[i][i-1], dp[i-1][j] + dis(i, j));
dp[i][j] = dp[i-1][j] + dis(i, i-1);
}
}
int ans = INF;
for (int i = 1; i <= n; i++)
ans = min(ans, dp[n+1][i] + dis(n+1, i));
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
d[1]=0;
int ans=0;
scanf("%d",&n);
for(int i=2;i<=n+1;i++)
{
int a;
scanf("%d%d",&a,&d[i]);
if(i==n+1)ans+=a*800;
ans+=10;
}
ans+=TSP_Dp();
printf("%d\n",ans);
}
}
3.分组背包
memset(dp,0,sizeof(dp));
for(int i=1;i<=1005;i++)
{
memset(dp2,0,sizeof(dp2));
for(int j=0;j<=1005;j++)dp2[j]=dp[j];
for(int j=0;j<mp[i].size();j++)
{
int num=mp[i][j];
for(int k=v;k>=a[num].cost;k--)
{
dp2[k]=max(dp2[k],dp[k-a[num].cost]+a[num].val);
}
}
for(int j=0;j<=1005;j++)dp[j]=max(dp[j],dp2[j]);
}
printf("%d\n",dp[v]);
4.在线倍增LCA
void Dfs(int u,int from)
{
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(v==from)continue;
d[v]=d[u]+1;
dist[v]=dist[u]+e[i].w;
p[v][0]=u;
Dfs(v,u);
}
}
void init()
{
for(int j=1;(1<<j)<=n;j++)
{
for(int i=1;i<=n;i++)
{
p[i][j]=p[p[i][j-1]][j-1];
}
}
}
int Lca(int x,int y)
{
if(d[x]>d[y])swap(x,y);
int f=d[y]-d[x];
for(int i=0;(1<<i)<=f;i++)
{
if((1<<i)&f)y=p[y][i];
}
if(x!=y)
{
for(int i=(int)log2(N);i>=0;i--)
{
if(p[x][i]!=p[y][i])
{
x=p[x][i];
y=p[y][i];
}
}
x=p[x][0];
}
return x;
}
5.斜率优化Dp
#include<stdio.h>
#include<string.h>
using namespace std;
int que[650000];
int a[650000];
int sum[650000];
int dp[650000];
int n,m;
int A(int j,int k)
{
return (dp[j]+sum[j]*sum[j])-(dp[k]+sum[k]*sum[k]);
}
int B(int j,int k)
{
return 2*(sum[j]-sum[k]);
}
int Val(int i,int j)
{
return dp[j]+(sum[i]-sum[j])*(sum[i]-sum[j])+m;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
sum[0]=0;
memset(dp,0,sizeof(dp));
memset(que,0,sizeof(que));
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];
int head=0,tot=0;
que[tot++]=0;
for(int i=1;i<=n;i++)
{
while(head+1<tot&&A(que[head+1],que[head])<=sum[i]*B(que[head+1],que[head]))head++;
dp[i]=Val(i,que[head]);
while(head+1<tot&&A(i,que[tot-1])*B(que[tot-1],que[tot-2])<=A(que[tot-1],que[tot-2])*B(i,que[tot-1]))tot--;
que[tot++]=i;
}
printf("%d\n",dp[n]);
}
}
单调队列
for(int i=1; i<=n; i++)
{
while(s<=e&&q[s].pos<i-m+1)s++;
while(s<=e&&q[e].val>a[i])e--;
e++,q[e].pos=i,q[e].val=a[i];
}
6.RMQ查询区间最大最小值
#include<stdio.h>
#include<string.h>
#include<cmath>
#include<iostream>
using namespace std;
int n,q;
int maxn[200005][20];
int minn[200005][20];
void ST()
{
int len=floor(log10(double(n))/log10(double(2)));
for(int j=1;j<=len;j++)
{
for(int i=1;i<=n+1-(1<<j);i++)
{
maxn[i][j]=max(maxn[i][j-1],maxn[i+(1<<(j-1))][j-1]);
minn[i][j]=min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]);
}
}
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
int tmp;
scanf("%d",&tmp);
maxn[i][0]=minn[i][0]=tmp;
}
ST();
for (int i = 1; i <= q; ++i){
int a,b;
scanf("%d%d", &a, &b);
if(a>b)swap(a, b);
int len= floor(log10(double(b-a+1))/log10(double(2)));
printf("%d\n",max(maxn[a][len], maxn[b-(1<<len)+1][len])-min(minn[a][len], minn[b-(1<<len)+1][len]));
}
return 0;
}
7.nlogn LIS
memset(dp,0,sizeof(dp));
memset(f,0x7f,sizeof(f));
for(int i = 1; i <= n; ++i)
{
int k = lower_bound(f + 1, f+ 1 + n, a[i]) - f;
dp[i] = k;
f[k] = a[i];
}
最长递减子序列
int find(int n,int key)
{
int left=0;
int right=n;
while(left<=right)
{
int mid=(left+right)/2;
if(res[mid]>key)
{
left=mid+1;
}
else
{
right=mid-1;
}
}
return left;
}
int Lis(int a[],int n)
{
int r=0;
res[r]=a[0];
r++;
for(int i=1;i<n;i++)
{
if(res[r-1]>a[i])
{
res[r]=a[i];
r++;
}
else
{
int loc=find(r,a[i]);
res[loc]=a[i];
}
}
return r;
}
最长不递减
int Slove(int n)
{
int c=0;
for(int i=1; i<=n; i++)
{
int t=a[i];
if(i==1) f[++c]=t;
else
{
if(t>=f[c]) f[++c]=t;
else
{
int pos=upper_bound(f+1,f+c,t)-f;//二分找到数组中比t大的第一个元素的的地址。
f[pos]=t;
}
}
}
return c;
}