–好久没写博客,真心没时间.
Closest Distance
Two men are moving concurrently, one man is moving from A to B and other man is moving from C to D. Initially the first man is at A, and the second man is at C. They maintain constant velocities such that when the first man reaches B, at the same time the second man reaches D. You can assume that A, B, C and D are 2D Cartesian co-ordinates. You have to find the minimum Euclidean distance between them along their path.
Input
Input starts with an integer T (≤ 1000), denoting the number of test cases.
Each case will contain eight integers: Ax, Ay, Bx, By, Cx, Cy, Dx, Dy. All the co-ordinates are between 0 and 100. (Ax, Ay) denotes A. (Bx, By) denotes B and so on.
Output
For each case, print the case number and the minimum distance between them along their path. Errors less than 10-6 will be ignored.
三分的题目,二分更进一步的情况,三分个三四十次答案就很精确了.
#include<bits/stdc++.h>
using namespace std;
struct gg{
double x;double y;
}a[3],b[3];int cas=0;double ans=0;
double getdis(gg a,gg b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double minnum(double a,double b,double c,double d)
{
return min(min(min(a,b),c),d);
}
void solve(gg l1,gg r1,gg l2,gg r2,int ci)
{ gg mid1,mid2,md1,md2;double dis1,dis2,dis3,dis4;
if(ci<=0)return;
mid1.x=(l1.x+r1.x)/2;
mid1.y=(l1.y+r1.y)/2;
mid2.x=(mid1.x+r1.x)/2;
mid2.y=(mid1.y+r1.y)/2;
md1.x=(l2.x+r2.x)/2;
md1.y=(l2.y+r2.y)/2;
md2.x=(md1.x+r2.x)/2;
md2.y=(md1.y+r2.y)/2;
dis1=getdis(l1,l2);
dis2=getdis(mid1,md1);
dis3=getdis(mid2,md2);
dis4=getdis(r1,r2);
if(minnum(dis1,dis2,dis3,dis4)==dis1)
ans=min(ans,dis1),solve(l1,mid1,l2,md1,ci-1);
else if(minnum(dis1,dis2,dis3,dis4)==dis2)
ans=min(ans,dis2),solve(l1,mid1,l2,md1,ci-1),solve(mid1,mid2,md1,md2,ci-1);
else if(minnum(dis1,dis2,dis3,dis4)==dis3)
ans=min(ans,dis3),solve(mid1,mid2,md1,md2,ci-1),solve(mid2,r1,md2,r2,ci-1);
else if(minnum(dis1,dis2,dis3,dis4)==dis4)
ans=min(ans,dis4),solve(mid2,r1,md2,r2,ci-1);
return;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{ ans=1e9+7;
scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&a[1].x,&a[1].y,&a[2].x,&a[2].y,&b[1].x,&b[1].y,&b[2].x,&b[2].y);
solve(a[1],a[2],b[1],b[2],40);
printf("Case %d: %.10lf\n",++cas,ans);
}
}
histogram
A histogram is a polygon composed of a sequence of rectangles aligned at a common base line. The rectangles have equal widths but may have different heights. For example, the figure shows the histogram that consists of rectangles with the heights 2, 1, 4, 5, 1, 3, 3 measured in units where the width of the rectangles is 1.
Usually, histograms are used to represent discrete distributions, e.g., the frequencies of characters in texts. Note that the order of the rectangles, i.e., their heights, is important. Calculate the area of the largest rectangle in a histogram that is aligned at the common base line, too. The figure on the right shows the largest aligned rectangle for the depicted histogram.
Input
Input starts with an integer T (≤ 20), denoting the number of test cases.
Each case contains a line with an integer N (1 ≤ N ≤ 30000) denoting the number of rectangles. The next line contains N space separated positive integers (≤ 30000) denoting the heights.
Output
For each case, print the case number and the largest rectangle that can be made.
经典题目,求一连串高度不同宽度为1的矩阵的最大矩形面积.刚开始一种方法都不会做,后来吴老师讲了4种,实现了3种,这里第四种就转自某泉神了.
解法一:单调栈
#include<bits/stdc++.h>
using namespace std;
struct gg{
int high;int id;int left;
}sqa[30010];
int main()
{
int t,n,cas=0,i,ans=0;gg tmp;
stack <gg> now;
scanf("%d",&t);
while(t--)
{ ans=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&sqa[i].high);
sqa[i].id=i;
}
for(i=1;i<=n;i++)
{
if(now.empty()==1||(sqa[i].high>=now.top().high))
{
sqa[i].left=now.empty()?1:now.top().id+1;
now.push(sqa[i]);
}
else
{
while(sqa[i].high<now.top().high)
{
tmp=now.top();now.pop();
ans=max(ans,tmp.high*(i-tmp.left));
if(now.empty()==1)break;
}
if(now.empty())
sqa[i].left=1;
else
sqa[i].left=now.top().id+1;
now.push(sqa[i]);
}
}
while(!now.empty())
{
tmp=now.top();now.pop();
ans=max(ans,tmp.high*(n+1-tmp.left));
}
printf("Case %d: %d\n",++cas,ans);
}
}
解法二:维护st表
#include<bits/stdc++.h>
using namespace std;
int Log[30010];
int dp[30010][18];
int mp[30010];
const int lg=17;
int ans=0;
void dfs(int l,int r)
{ if(l>r)return;
if(l==r)
{ans=max(ans,mp[l]);return;}
int tmp=Log[r-l+1],num;
if(mp[dp[l][tmp]]>mp[dp[r-(1<<tmp)+1][tmp]])
num=dp[r-(1<<tmp)+1][tmp];
else num=dp[l][tmp];
ans=max(ans,(r-l+1)*mp[num]);
dfs(l,num-1);
dfs(num+1,r);
return ;
}
int main()
{
int t,i,n,j,cas=0;
Log[0]=-1;
for(i=1;i<=30000;i++)
Log[i]=Log[i>>1]+1;
scanf("%d",&t);
while(t--)
{ ans=0;
memset(dp,0,sizeof dp);
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&mp[i]);
dp[i][0]=i;
}
for(i=1;i<lg;i++)
{
int limit=n-(1<<i)+1;
for(j=1;j<=limit;j++)
{
if(mp[dp[j][i-1]]<=mp[dp[j+(1<<i>>1)][i-1]])
dp[j][i]=dp[j][i-1];
else
dp[j][i]=dp[j+(1<<i>>1)][i-1];
}
}
dfs(1,n);
printf("Case %d: %d\n",++cas,ans);
}
}
解法三:笛卡尔树
#include<bits/stdc++.h>
using namespace std;
struct gg{
int left;int right;int cnt;
}pt[30010];int root=-1,ans=0;
stack<int>now;
void doit(int a,int num)
{ int tmp=-1,tmpp;
while(a<pt[now.top()].cnt)
{tmp=now.top();now.pop();if(now.empty())break;}
if(tmp!=-1)pt[num].left=tmp;
if(now.empty())
root=num;
else
{pt[now.top()].right=num;}
now.push(num);
}
int dfs(int now)
{int tmp=1;
if(pt[now].left)
tmp+=dfs(pt[now].left);
if(pt[now].right)
tmp+=dfs(pt[now].right);
ans=max(ans,tmp*pt[now].cnt);
return tmp;
}
int main()
{
int t,n,i,tmp,cas=0;
scanf("%d",&t);
while(t--)
{ while(!now.empty())
now.pop();
root=1;ans=0;
for(i=1;i<=30010;i++)
pt[i].cnt=pt[i].left=pt[i].right=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
{scanf("%d",&tmp);
pt[i].cnt=tmp;
if(i==1)now.push(i);
else doit(tmp,i);}
dfs(root);
printf("Case %d: %d\n",++cas,ans);
}
}
解法四:kmp思想(转自泉神)
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define N 100005
#define INF 0x3f3f3f3f
int lft[N],rght[N],value[N];
int ans=-INF,n,T;
inline int read(){
int x=0;char c=getchar();bool flag=0;
while(c<'0'||c>'9') {if(c=='-')flag=1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0'; c=getchar();}
flag?-x:x;
return x;
}
int main()
{
T=read();
for(int loc=1;loc<=T;loc++)
{
n=read();
for(int i=1; i<=n; i++)
value[i]=read();
for(int i=1; i<=n; i++) { lft[i]=i;while(lft[i]-1>=0&&value[lft[i]-1]>=value[i]) lft[i]=lft[lft[i]-1]; }
for(int i=n; i>=1; i--) { rght[i]=i;while(rght[i]+1<=n&&value[rght[i]+1]>=value[i]) rght[i]=rght[rght[i]+1]; }
for(int i=1; i<=n; i++) ans=std::max(ans,(rght[i]-lft[i]+1)*value[i]);
printf("Case %d: %d\n",loc,ans);
ans=-INF;
}
return 0;
}
其中笛卡尔树比较6,建了一棵根节点下都比根大的树,建好一次dfs出结果.
(笛卡尔树:笛卡尔树是一棵二叉树,树的每个节点有两个值,一个为key,一个为value。光看key的话,笛卡尔树是一棵二叉搜索树,每个节点的左子树的key都比它小,右子树都比它大)
DNA Sequence
You are given a list of strings over the alphabet A (for adenine), C (cytosine), G (guanine), and T (thymine), and your task is to find the shortest string (which is typically not listed) that contains all given strings as substrings. If there are several such strings of shortest length, find the smallest in alphabetical/lexicographical order.
Input
Input starts with an integer T (≤ 35), denoting the number of test cases.
Each case starts with an integer denoting the number of strings n (1 ≤ n ≤ 15) in a single line. Then these n strings (1 ≤ length ≤ 100) follow, one on each line, and they consist of the letters ‘A’, ‘C’, ‘G’ and ‘T’ only.
Output
For each case, print the case number and the shortest (and lexicographically smallest) string according to the description above.
Sample Input
2
2
TGCACA
CAT
3
TAC
ACT
CTA
Sample Output
Case 1: TGCACAT
Case 2: ACTAC
真心做到呕心沥血的题目,wa了30次…最终发现被题意杀(英语差)了,以为是把所有串接起来,重复部分去掉,结果之后才知道也可以是包含(如aba,b是aba而不是abab),之后加了预处理去掉会被包含的串就过了.
蒟蒻思路 :预处理了两个string数组,一个mp[i][j]放把j丢到i前面要加的字符串(便于最后搞出结果),一个mpp[i][j]表示j在前面i在后面时i的不与j重复的串.(例如,s[0]=cat,s[1]=tgcaca则mp[i][j]=tgca,mpp[i][j]=ca.)之后就是状压了,两维dp表示开头串编号以及取的状态.注意:最好先排个序最后比最终答案方便.
#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
string st[15],s[15],mp[15][15],mpp[15][15];bool ok[15];
int dp[15][1<<15],fa[15][1<<15];
inline void pp(int a,int b)
{ int i,j,len1=s[a].length(),len2=s[b].length(),ans=-1;string ret,rett;
for(j=0;j<len2;j++)
{if(s[b][j]==s[a][0])
{int flag=0;
for(i=j+1;i<len2;i++)
if(s[b][i]!=s[a][i-j]){flag=1;break;}
if(flag==0){ans=j;break;}}}
if(ans==-1)ret=s[b],rett=s[a];
else {for(i=0;i<ans;i++)ret+=s[b][i];for(i=len2-ans;i<len1;i++)rett+=s[a][i];}
mpp[a][b]=rett;mp[a][b]=ret;
}
inline string get_ans(int now,int end)
{string ans;
int tmp;
while(end!=-1)
{if(fa[end][now]==-1)ans+=s[end];
else ans+=mp[fa[end][now]][end];
tmp=end;end=fa[end][now];now-=(1<<tmp);}
return ans;
}
int main()
{ int t,n,i,j,k,x,cas=0,cnt;string sss,ss;bool flg;
scanf("%d",&t);
while(t--)
{ memset(dp,0x3f,sizeof dp);memset(fa,-1,sizeof fa);
memset(ok,0,sizeof ok);cnt=0;
scanf("%d",&n);
for(i=0;i<n;i++)
cin>>st[i];
for(i=0;i<n;i++)
{for(j=0;j<n;j++)
{if((j==i)||(st[j].length()>=st[i].length()))continue;
for(k=0;k<st[i].length();k++)
{if(st[i][k]==st[j][0])
{flg=0;
for(x=0;x<st[j].length();x++)
if(k+x==st[i].length()||st[i][k+x]!=st[j][x]){flg=1;break;}
if(flg==0){ok[j]=1;break;}}}}}
for(i=0;i<n;i++)
if(ok[i]==0)s[cnt++]=st[i];n=cnt;
sort(s,s+n);
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(i!=j)pp(i,j);
for(i=0;i<n;i++)
dp[i][(1<<i)]=s[i].length();
for(j=1;j<=(1<<n)-1;j++)
for(x=0;x<n;x++)
{if(!((1<<x)&j))continue;
for(k=0;k<n;k++)
{if((1<<k)&j)continue;
if(dp[k][j|(1<<k)]>(dp[x][j]+mp[x][k].length()))
fa[k][j|(1<<k)]=x,dp[k][j|(1<<k)]=dp[x][j]+mp[x][k].length();
else if(dp[k][j|(1<<k)]==(dp[x][j]+mp[x][k].length()))
if(mpp[x][k]<mpp[fa[k][j|(1<<k)]][k])fa[k][j|(1<<k)]=x;
}
}
int ans=1e9;
for(i=0;i<n;i++)
{if(ans>dp[i][(1<<n)-1])
{ans=dp[i][(1<<n)-1];
ss=get_ans(((1<<n)-1),i);}}
printf("Case %d: ",++cas);cout<<ss<<endl;
}
}