最大子矩阵
一、题目
二、解法
设 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]为第一列选 i i i个,第二列选 j j j个,选出 k k k个矩形的最大得分。
{ d p [ i ] [ j ] [ k ] = d p [ i − 1 ] [ j ] [ k ] ( i > 0 ) d p [ i ] [ j ] [ k ] = d p [ i ] [ j − 1 ] [ k ] ( j > 0 ) d p [ i ] [ j ] [ k ] = d p [ p ] [ j ] [ k − 1 ] + p 1 [ i ] − p 1 [ p ] ( p < i ) d p [ i ] [ j ] [ k ] = d p [ i ] [ p ] [ k − 1 ] + p 2 [ i ] − p 2 [ p ] ( p < j ) d p [ i ] [ j ] [ k ] = d p [ p ] [ p ] [ k − 1 ] + p 1 [ i ] − p 1 [ p ] + p 2 [ i ] − p 2 [ p ] ( i = j ∧ p < i ) \begin{cases} dp[i][j][k]=dp[i-1][j][k] & (i>0) \\ dp[i][j][k]=dp[i][j-1][k] & (j>0) \\ dp[i][j][k]=dp[p][j][k-1]+p1[i]-p1[p] & (p<i)\\ dp[i][j][k]=dp[i][p][k-1]+p2[i]-p2[p] & (p<j)\\ dp[i][j][k]=dp[p][p][k-1]+p1[i]-p1[p]+p2[i]-p2[p] & (i=j \space \wedge \space p<i) \end{cases} ⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧dp[i][j][k]=dp[i−1][j][k]dp[i][j][k]=dp[i][j−1][k]dp[i][j][k]=dp[p][j][k−1]+p1[i]−p1[p]dp[i][j][k]=dp[i][p][k−1]+p2[i]−p2[p]dp[i][j][k]=dp[p][p][k−1]+p1[i]−p1[p]+p2[i]−p2[p](i>0)(j>0)(p<i)(p<j)(i=j ∧ p<i)
这样我们就得到了一个 O ( n 3 k ) O(n^3k) O(n3k)的算法。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,k,p1[105],p2[105];
int f[105][11],dp[105][105][11];
int main()
{
n=read();m=read();k=read();
for(int i=1;i<=n;++i)
{
p1[i]=p1[i-1]+read();
if(m==2)p2[i]=p2[i-1]+read();
}
dp[0][0][0]=0;
for(int l=1;l<=k;l++)
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
{
if(!i && !j) continue;
if(i)dp[i][j][l]=dp[i-1][j][l];
if(j)dp[i][j][l]=max(dp[i][j-1][l],dp[i][j][l]);
for(int p=0;p<i;p++)
dp[i][j][l]=max(dp[i][j][l],dp[p][j][l-1]+p1[i]-p1[p]);
for(int p=0;p<j;p++)
dp[i][j][l]=max(dp[i][j][l],dp[i][p][l-1]+p2[j]-p2[p]);
if(i==j)
for(int p=0;p<i;p++)
dp[i][j][l]=max(dp[i][j][l],dp[p][p][l-1]+p1[i]-p1[p]+p2[j]-p2[p]);
}
printf("%d\n",dp[n][n][k]);
}
序列的第 k 个数
一、题目
二、解法
签到题,实在太水了。
#include <cstdio>
#define int long long
#define mod(x) ((x)%MOD+MOD)%MOD
const int MOD = 200907;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int T,a,b,c,k;
int qkpow(int a,int b)
{
int res=1;
while(b>0)
{
if(b&1) res=res*a%MOD;
a=a*a%MOD;
b>>=1;
}
return res;
}
signed main()
{
T=read();
while(T--)
{
a=read();b=read();c=read();k=read();
if(b-a==c-b)
{
printf("%d\n",mod(a+(k-1)*(b-a)));
continue;
}
int d=b/a;
printf("%d\n",mod(a*qkpow(d,k-1)));
}
}
Star Way To Heaven
一、题目
二、解法
考虑二分答案
t
t
t,以每个星星为圆心作圆,然后就是看从
x
x
x轴开始每次走不超过
2
t
2t
2t走到上顶面,也就是考虑星星能不能封路,时间复杂度
O
(
k
2
log
m
)
O(k^2\log m)
O(k2logm)。
发现可以建一棵最小生成树(这里的说法不是很严谨,应该生成到上下联通),然后取最大的边即可,时间复杂度
O
(
k
2
)
O(k^2)
O(k2)。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;
#define int long long
const int MAXN = 6005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,k,ans,x[MAXN],y[MAXN],dis[MAXN];
int dist(int i,int j)
{
return (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
}
signed main()
{
n=read();m=read();k=read();
for(int i=1;i<=k;i++)
x[i]=read(),y[i]=read();
memset(dis,0x3f,sizeof dis);
dis[k+2]=0;
for(int i=1;i<=k+2;i++)
{
int id=0;
for(int j=1;j<=k+2;j++)
{
if(dis[id]>dis[j] && dis[j]!=-1)
id=j;
}
ans=max(ans,dis[id]);
if(id==k+1) break;
dis[id]=-1;
for(int j=1;j<=k+1;j++)
{
if(j==k+1) dis[j]=min(dis[j],(m-y[id])*(m-y[id]));
else if(id==k+2) dis[j]=min(dis[j],y[j]*y[j]);
else dis[j]=min(dis[j],dist(id,j));
}
}
printf("%.9lf",sqrt(ans)*0.5);
}