【题目链接】http://evaluator.hsin.hr/login.php?redirect=index.php
【题目大意】
给出一个尺寸N。
你需要取一个2^k (k是任你选的)的巧克力出来,然后切若干刀(每刀把一个巧克力切开成两半一样大小的)
最终在其中取出若干个块巧克力,使得加起来的尺寸等于N。
最终输出2^k和切得刀数。
在保证2^k最小的前提下,切刀数要最少。
【算法分析】
同属于被秒杀题= =
假如N=2^k,那么直接输出 2^k 0
否则输出最小的一个k满足,N<2^k (用log2求就可以了),
然后输出将n变成二进制以后从个位数上去的第一个“1”和k的差即可。
【其它】
YY一下就懂了。
【CODE】
#include
scanf("%d",&n);
LG=(int)(log(n)/log(2)+1e-7);
if (1<
LG++;
i=0;
while (n%2==0){
i++;
n/=2;
}
printf("%d %dn",1<
}
作者存档:edward_mj
[COCI 2009/2010 – Constest #7 SPAVANAC]水题
【题目地址】http://evaluator.hsin.hr/login.php?redirect=index.php
【题目大意】
给出一个24小时制的时间,让你输出它的前45分钟时多少。
【算法分析】
类a-b problems
【其它】
。。。其实我不想写的,但是为了完整性,还是写一下。。。
【CODE】
#include
int H,M;
scanf("%d%d",&H,&M);
M-=45;
if (M<0){M+=60; H--;}
if (H<0) H+=24;
printf("%d %dn",H,M);
}
[BOI2010 bins]一个桶
【BOI链接】http://www.ut.ee/boi/
【题目大意】
按顺序给出n<=20000个箱子,他们的尺寸m<=1000。
求一个最大的k,使得前k个和第k+1个到2*k个箱子之间能一一匹配。
能匹配的定义是i∈[1,k] 且 j∈[k+1,2*k] 同时Size[i]
因为m<=1000,开一个1000的桶,然后从k从n/2开始枚举下来,维护一下。
由于O(nm)都不会超时,直接每次都暴力判断就好了。
【CODE】
#include
bool flag(){
int num1=0,num2=0,i;
for (i=1;i<=m;i++){
if (num1
num2+=t2[i];
if (num1
return true;
}
int main(){
int i,k,ans=0;
memset(t1,0,sizeof(t1));
memset(t2,0,sizeof(t2));
freopen("bins.in","r",stdin);
freopen("bins.out","w",stdout);
scanf("%d%d",&m,&n);
for (i=1;i<=n;i++)
scanf("%d",&a[i]);
k=n/2;
for (i=1;i<=k;i++) t1[a[i]]++;
for (i=k+1;i<=2*k;i++) t2[a[i]]++;
for (k=n/2;k>=0;k–){
if (flag()){
ans=k;
break;
}
if (!k) break;
t1[a[k]]–;
t2[a[k]]++;
t2[a[2*k]]–;
t2[a[2*k-1]]–;
}
printf("%dn",ans);
}
[BOI2010 pcb]贪心、平衡树
【题目和数据下载地址】http://www.ut.ee/boi/
【题目大意】
给定n条电线(Ai,Bi),其中A点都在一矩形箱子的上方,B点都在矩形箱子的下方。
其中Ai和Bi分别表示他们的横坐标。
然后这些电线交叉的话会短路,问至少要弄多少层(每层之间完全隔开),才能把这些电线全连上而又不短路。
数据保证Ai和Bi是2*n个不相同的整数。
【算法分析】
显然,假如对于一对电线(i,j),Ai
显然,假如Bi
于是我们可以贪心一下。
对于每个递增序列,记录它的最后一个就可以了,因为前面的已经和扩展无关了。
然后每一次对于一个Bi,在开了的ans个递增序列里找一个这样的序列i,满足:
Max(End[i] :End[i]
遇过找不到这样一个序列,那么就新开一个序列,ans++,End[ans]=Bi。
最后输出ans即可。
然后对于上面那个找Max(End[i] :End[i]
#include
struct Point{int x,y;}a[N];
int n,ans;
struct SBT_Type{
struct Node{int l,r,key,s;}tr[N*3];
int tot,root;
void update(int p){if (p) tr[p].s=tr[tr[p].l].s+tr[tr[p].r].s+1;}
int max(int x,int y){return x>y?x:y;}
void left(int &p){
int k=tr[p].r;
tr[p].r=tr[k].l;
tr[k].l=p;
update(p);
update(k);
p=k;
}
void right(int &p){
int k=tr[p].l;
tr[p].l=tr[k].r;
tr[k].r=p;
update(p);
update(k);
p=k;
}
void repair(int &p){
if (!p) return;
bool flag=false;
if (tr[tr[tr[p].l].l].s>tr[tr[p].r].s){
right(p);
flag=true;
}
if (tr[tr[tr[p].l].r].s>tr[tr[p].r].s){
left(tr[p].l);
right(p);
flag=true;
}
if (tr[tr[tr[p].r].r].s>tr[tr[p].l].s){
left(p);
flag=true;
}
if (tr[tr[tr[p].r].l].s>tr[tr[p].l].s){
right(tr[p].r);
left(p);
flag=true;
}
if (flag){
repair(tr[p].l);
repair(tr[p].r);
repair(p);
}
}
int del(int &p,int key){
tr[p].s–;
if (key
if (!tr[p].l || !tr[p].r) p=tr[p].l+tr[p].r;
else tr[p].key=del(tr[p].l,0x7FFFFFFF);
return res;
}
if (key
}
void ins(int &p,int key){
if (!p){
p=++tot;
tr[p].l=tr[p].r=0; tr[p].s=1; tr[p].key=key;
return;
}
tr[p].s++;
if (key
repair(p);
}
int Find(int p,int key){
if (!p) return -0x7FFFFFFF;
if (key>tr[p].key) return max(tr[p].key,Find(tr[p].r,key));
return Find(tr[p].l,key);
}
}SBT;
int cmp(const void *x,const void *y){
return ((Point*)x)->x-((Point*)y)->x;
}
int main(){
freopen("pcb.in","r",stdin);
freopen("pcb.out","w",stdout);
int i,tmp;
scanf("%d",&n);
for (i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
qsort(a+1,n,sizeof(Point),cmp);
SBT.tot=SBT.root=ans=0;
for (i=1;i<=n;i++){
tmp=SBT.Find(SBT.root,a[i].y);
if (tmp==-0x7FFFFFFF){
ans++;
SBT.ins(SBT.root,a[i].y);
}
else{
SBT.del(SBT.root,tmp);
SBT.ins(SBT.root,a[i].y);
}
}
printf("%dn",ans);
}
[ZSOI 股票投资]包含贪心思想的动态规划
Description

Input

Output
对每组数据,输出一行,包含一个保留3位小数的实数,表示你能获得的最多现金。答案保证不会超过1e15。
Sample Input
1
5000 0.001 5 0.003
6
20 21 20 19 20 19
Sample Output
5332.000

【算法分析】
容易发现,如果是最优解的话,必然可以将时间划分成x个阶段,
每个阶段是由一个尽量买,和一个尽量卖所组成。
然后,
F[i]表示第i天最多剩多少现金
Gmax[i]表示第i天最多持有多少股
Grest[i]表示第i天持Gmax[i]股,剩下最多多少钱。
然后转移时就分当前位置是尽量买之后的和尽量卖之后的讨论。
维护一下就可以了。
【CODE】
#include
const int INF=1000000000;
int n,tot;
double C,S1,S2,T,prize[N],F[N],Gmax[N],Grest[N];
inline double max(double x,double y){return x>y?x:y;}
double Buy(double x,double p){
int l=0,r=INF,mid;
double G;
while (l+1
G=p*mid*100;
if (G+G*T+max(G*S1,S2)<=x) l=mid;
else r=mid-1;
}
G=p*r*100;
if (G+G*T+max(G*S1,S2)<=x) return 100.0*r;
else return 100.0*l;
}
double Rest(double x,double b,double p){
double G=b*p;
return x-(G+G*T+max(G*S1,S2));
}
double Sell(double b,double r,double p){
double G=b*p;
return r+G-G*T-max(G*S1,S2);
}
void dp(){
int i;
double k;
memset(F,0,sizeof(F));
F[0]=C; Gmax[0]=0; Grest[0]=C;
for (i=1;i<=n;i++){
Gmax[i]=Gmax[i-1];
Grest[i]=Grest[i-1];
F[i]=max(F[i-1],Sell(Gmax[i],Grest[i],prize[i]));
k=Buy(F[i-1],prize[i]);
if (Gmax[i]
Gmax[i]=k;
}
}
printf("%.3lfn",F[n]);
}
int main(){
freopen("stock.in","r",stdin);
freopen("stock.out","w",stdout);
int Tc;
scanf("%d",&Tc);
for (int i=1;i<=Tc;i++){
scanf("%lf%lf%lf%lf%d",&C,&S1,&S2,&T,&n);
for (int i=1;i<=n;i++) scanf("%lf",&prize[i]);
dp();
}
}