您的位置:首页 > 其它

暑假习题 四

2015-07-27 08:12 323 查看
巧克力

巧克力

[Description]

yaoyiyao 带来了一块N*M*K 的巧克力,但是这一天机房的人很多,为了公平,tsyao 提议

先分成1*1*1 的,然后每人那一块,剩下的给yaoyiyao(毕竟是他的嘛)

但是yaoyiyao 不想把力气花在这上面,于是就交给了FinalSix 神牛,FinalSix 说我们应该用

最小的代价来划分这个巧克力。

有两种划分方法:

① 用手,每次只能掰一块,至于从哪里掰随便

② 用刀,每次可以将几块巧克力重起来,然后从某个位置一刀切下来

FinalSix 不想动手算了,想知道分别使用这两种方法的最少次数分别是多少

[Input]

一行三个整数N,M,K,之间用一个空格隔开

[Output]

两行,每行一个整数,分别表示两种方法的最少次数。

分析:

巧克力

第一问应该很好得知答案应该是N*M*K–1

首先我们在N 那一边切 N-1 刀变成N 块 1*M*K 的

然后每块1*M*K 的我们切M-1 刀,共 N×(M-1) 刀变成N*M 块1*1*K 的

然后每块再切K-1 刀即全部变成1*1*1,共 N*M*(K-1) 刀

最后加起来化简 N*M*K-1 刀

第二问因为可以重在一起切,所以我们每次尽可能地在中间切肯定是最优方案!然后切下来的两块是可以重在一起看成一块来处理的,所以切下来的一块是可以不管了的。最终的解法就是每次/2 就ok 了。

#include <cstdio>

long long n,m,k;

int main()
{
scanf("%d%d%d",&n,&m,&k);
printf("%I64d\n",(long long)n*m*k-1);
long long ans=0;
while(n>1)
{
ans++;
if(n%2)n=n/2+1;
else n=n/2;
}
while(m>1)
{
ans++;
if(m%2)m=m/2+1;
else m=m/2;
}
while(k>1)
{
ans++;
if(k%2)k=k/2+1;
else k=k/2;
}
printf("%I64d",ans);
return 0;
}


序列

[Description]

有一天OJ 给Jiangzh 了一个序列,但是OJ 给的任务没有省选operation 那么变态,OJ 只需

要Jiangzh 做两件事:

① 求出这个序列的最长上升子序列长度

② 这个序列中满足 i < j < k Ai < Aj > Ak 关系的序列个数

[Input]

第一行一个整数N,表示这个序列有N 个整数

第二行N 个整数Ai

[Output]

两行,每行一个整数分别为两个问题的答案

[Sample 1]

sequence.in

5

1 2 3 4 5

sequence.out

5

0

样例解释:最长上升子序列长度为5,满足条件②的序列有0 个

分析:

第一问:LIS

第二问:求序列个数

O(N^3)算法:枚举i,j,k,判断

O(N^2)算法:枚举j 作为中点,然后向左扫描得到比Aj 小的数的个数L,向右扫描

得到比Aj 小的数的个数R,然后利用乘法原理得到以j 作为中点的序列有L*R 个,把所

有的L*R 加起来即可

O(Nlog2 N)算法:和上面一样,只是找L 和R 的时候利用线段树。

#include<cstdio>
#include<cstring>
const int N=200000+10;
const int maxp=200000;
int n,a
;
int val[N*4];
int l
,r
;
int c
;

int LIS()
{
int len=0;
for(int i=1;i<=n;i++)
{
int l=1,r=len,m;
while(l<=r)
{
m=(l+r)>>1;
if(a[i]>c[m]) l=m+1;
else r=m-1;
}
c[l]=a[i];
if(l>len) len=l;
}
return len;
}

void change(int p,int l,int r,int a)
{
if(l==r && l==a)
{
val[p]++;//节点p包含数的个数增加1
return;
}
int m=(l+r)>>1;
if(a<=m) change(p<<1,l,m,a);
if(a>m) change((p<<1)+1,m+1,r,a);
val[p]=val[p<<1]+val[(p<<1)+1];
}
int query(int p,int l,int r,int a,int b)//查询线段树中[a,b]区间内比某数小的数的个数
{
if(a<=l && b>=r) return val[p];
int m=(l+r)>>1,x1=0,x2=0;
if(a<=m) x1=query(p<<1,l,m,a,b);
if(b>m) x2=query((p<<1)+1,m+1,r,a,b);
return x1+x2;
}

long long solve()
{
for(int i=1;i<=n;i++)
{
l[i]=query(1,0,maxp,0,a[i]-1);
change(1,0,maxp,a[i]);
}
memset(val,0,sizeof(val));
for(int i=n;i>=1;i--)
{
r[i]=query(1,0,maxp,0,a[i]-1);
change(1,0,maxp,a[i]);
}
long long res=0;
for(int i=1;i<=n;i++) res+=(long long)l[i]*r[i];
return res;
}

int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
printf("%d\n",LIS());
printf("%I64d\n",solve());
return 0;
}


给力否?

[Description]

还记得Day1 的时候yuyanggo 去偷玉米吗?他最后被农场主逮了……

yuyanggo 想把玉米丢了,但是他的狗始终不干,没办法,只好带着玉米跑了~

由于玉米很重,逃跑的时候会消耗yuyangg
bb8e
o 的体力值,每跑1m 就会消耗一个体力值,所

以yuyanggo 必须选择一条最近的路(或者说是最后剩余体力值最多的路)跑回来。

有N 个点,1 为玉米地,N 为机房。

由于地形特殊,会有下坡路(用距离为负数表示),如-z,如果|z|<=N*10 那么,

yuyanggo 就不需要消耗体力,但是如果 |z|>N*10 就会因为坡太陡了不能走。

上面的规则仅在下坡路适用,其他的路每走1m 就消耗一个体力值。

情况紧急,yuyanggo 拿出了无线通话器,寻求信奥班的帮忙,告诉他怎么走最近。

[Input]

第1 行,一个整数P,表示yuyanggo 一开始的体力值

第2 行,两个整数,N 个点和M 条边

第3 ~ M+2 行,每行三个整数,x y z,表示x 到y 有一条长度为z(单位:m)的边,保证

x 到y 只会存在一条边。每两个整数用一个空格隔开.

[Output]

如果不能在体力耗尽之前跑回来或者没有完整的路跑回来,就输出“bu gei li a.”

如果能跑回来,就输出三行,第一行一个整数为剩余体力值,第二行一个整数为走过的点

数N(包含起终点),第三行N 个整数,即走过的路径,相邻整数用“->”(红色加粗部

分,不含引号,两个字符均为英文字符)分割。最后可能有多种方案,任意输出一种即可。

geili.in

10

4 6

1 2 5

1 3 3

2 3 5

3 2 2

3 4 7

2 4 5

geili.out

0

3

1->3->4

分析:

最短路的变形。

建图,用链表,注意是x 到y 的单向边。遇到下坡,判断一下,|z|<=N*10 就直接连称边权为0,|z|>N*10 就不连边,表示不能走。

然后就是最短路了。

用一个pre[]来记录路径就行了。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int inf=0x3f3f3f;
int n,m,po;
int head[200005];
int vis[200005];
int dis[200005];
int p[200005];

struct edge{
int v,w,next;
}e[200005];
int ans[200005];
int k=1;

void adde(int u,int v,int w)
{
e[k].v=v;
e[k].w=w;
e[k].next=head[u];
head[u]=k++;
}

void readdata(){
memset(head,-1,sizeof(head));
memset(dis,inf,sizeof(dis));//将所有dis初始化为inf
scanf("%d",&po);
scanf("%d %d",&n,&m);
int a,b,c;
for(int i=1; i<=m; i++)
{
scanf("%d%d%d",&a,&b,&c);
if(c<0)
{
c=-c;
if(c<=10*n) c=0;
else continue;
}
adde(a,b,c);
}
}
int l=0;
void dijkstra()
{
typedef pair<int,int>pii;
priority_queue<pii,vector<pii>,greater<pii> >q;
dis[1]=0;
q.push(make_pair(dis[1],1));
while(!q.empty())
{
int u=q.top().second;
q.pop();
if(vis[u])continue;
vis[u]=1;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w)
{       p[v]=u;
dis[v]=dis[u]+e[i].w;
q.push(make_pair(dis[v],v));
}
}
}
}

int main()
{
readdata();
dijkstra();
int pas=1;
for(int i=1;i<=m;i++)
{
if(p[i]>0 && p[i]!=p[i-1])pas++;
}
if(dis
>po)printf("bu gei li a.");
else
{printf("%d\n",po-dis
);

int res,i=n;
ans[res=1]=n;

do{
i=p[i];
ans[++res]=i;
}while(i!=1);
printf("%d\n",res);
for(int i=res;i>1;i--)printf("%d->",ans[i]);
printf("%d\n",ans[1]);
return 0;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: