大大出的题

大大经常吐槽没有人补,所以我决定做一个

A. APA of Orz Pandas

题意:给你一个包含+-*/%和()的表达式,让你把它转化成java里BigInteger的形式

大概就像这样 "a.add(b).remainder(M).multiply(d.substract(e.multiply(f)).add(g.divide(h))).multiply (BigInteger.ValueOf(233)) ... ..."

输入的串长度<=1000

有意思的模拟题,不是很好写

首先要看清题,a+(b+c)应该输出为a.add(b.add(c))而不是a.add(b).add(c)

我之前看错题,使得这个题难度高了一点,但是那样也可以做,只需预处理无用括号即可

观察可以发现,不存在(a.add(b)).add(c)这种说法,也就是说,括号的本质作用是改变运算顺序,然后把括号里的表达式作为一个对象参与运算

那么就可以把括号里的东西看成一个变量,然后问题就转化为没有括号的表达式的处理

对于括号中的括号,可以把输出写成参数l和r的函数,功能为输出下标为[l,r]的子区间,然后递归处理

接下来的问题是找到输出序列中括号的包含范围,例如a+b*c要表示为a.add(b.multiply(c)),如何找到add右括号的位置

可以开一个栈

左括号可以直接压入

当压入右括号时,可以把左右括号中的所有运算符,包括括号全部湮灭

当压入+-时,可以把所有栈头的运算符湮灭,并令其右括号的位置在此运算符之前,但应在遇到左括号时停止

当压入*/%时,可以把栈头的*/%运算符湮灭,并令其右括号的位置在此运算符之前,但应遇到左括号或+-为止

代码:

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
char fc[][]={
{'a','d','d',},
{'s','u','b','s','t','r','a','c','t',},
{'m','u','l','t','i','p','l','y',},
{'d','i','v','i','d','e',},
{'r','e','m','a','i','n','d','e','r',}
};
int fs[];
char s[]; int n;
char q[]; int p[],hd=;
bool flg[];
int nxt[];
bool chck(char x){ return x=='+'||x=='-'||x=='*'||x=='/'||x=='%'||x=='('||x==')';}
bool chck1(char x){ return x=='+'||x=='-'||!x;}
bool chck2(char x){ return x=='*'||x=='/'||x=='%'||!x;}
void ot(int x,int y){
for(int i=x;i<=y;++i)if(s[i] && s[i]!='(' && s[i]!=')'){
if(!chck(s[i])) printf("%c",s[i]);
else{
printf(".");
for(int j=;fc[fs[(int)s[i]]][j];++j) printf("%c",fc[fs[(int)s[i]]][j]);
printf("("); ot(i+,nxt[i]); printf(")");
i=nxt[i];
}
}
}
void prvs(){
fs['+']=,fs['-']=,fs['*']=,fs['/']=,fs['%']=;
hd=;
for(int i=;i<=n;++i) flg[i]=false;
s[]=,s[n+]=;
for(int i=;i<=n;++i) nxt[i]=;
}
int main(){
//freopen("ddd.in","r",stdin);
while(scanf("%s",s+)!=EOF){
n=strlen(s+); prvs();
for(int i=;i<=n;++i)if(chck(s[i])){
if(s[i]==')'){
bool mk1=false,mk2=false;
for(;q[hd]!='(';--hd){
if(q[hd]=='+'||q[hd]=='-') mk1=true;
if(q[hd]=='*'||q[hd]=='/'||q[hd]=='%') mk2=true;
}
if((chck2(s[i+])||chck2(s[p[hd]-])) && !mk1){
if(!mk2) flg[i]=true,flg[p[hd]]=true;
if(s[p[hd]-]!='/'&&s[p[hd]-]!='%') flg[i]=true,flg[p[hd]]=true;
}
if(s[i+]==')' && s[p[hd]-]=='(')
flg[i]=true,flg[p[hd]]=true;
if(chck1(s[i+]) && chck1(s[p[hd]-]))
flg[i]=true,flg[p[hd]]=true;
nxt[p[hd]]=i;
--hd;
}
else q[++hd]=s[i]; p[hd]=i;
}
hd=;
for(int i=;i<=n;++i){
//if(flg[i]) s[i]=0;
if(s[i] && chck(s[i])){
if(s[i]=='(') q[++hd]=s[i],p[hd]=i;
if(s[i]==')'){
for(;q[hd]!='(';--hd) nxt[p[hd]]=i-;
--hd;
}
if(chck1(s[i])){
for(;hd && q[hd]!='(';--hd) nxt[p[hd]]=i-;
q[++hd]=s[i],p[hd]=i;
}
if(chck2(s[i])){
for(;hd && q[hd]!='(' && !chck1(q[hd]);--hd) nxt[p[hd]]=i-;
q[++hd]=s[i],p[hd]=i;
}
}
}
for(;hd;--hd) nxt[p[hd]]=n;
/*for(int i=1;i<=n;++i) cout<<i<<" ";
cout<<endl;
for(int i=1;i<=n;++i) cout<<s[i]<<" ";
cout<<endl;
for(int i=1;i<=n;++i) cout<<nxt[i]<<" ";
cout<<endl;*/
ot(,n); printf("\n");
}
return ;
}  

B. Brute Force of Orz Pandas

题意:

给你一个输出n层汉诺塔最优解的详细步骤的程序

输入n和k,要求你输入当此程序输入为n时的第k行输入,如果k大于总行数则输出Orz

n,k<=10^18

最开始的思路时数学/推公式/找规律解决,这样其实比较难搞

我们发现,直接运行给出的程序不可行是因为给出的程序会遍历每一种情况,而如果我们发现调用某个递归函数导致的输出大于当前查询的行数,完全可以跳过它

而对于每个递归的输出行数,可以由公式快速得到

那么类似在平衡树上查找第k大的方式

对于每一层,如果k小于第一个递归将输出的行数,那么进第一个递归,递归解决问题

如果等于第一个递归输出行数+1,说明找到我们的答案

如果大于第一个递归输出行数+1,就令k-=第一个递归输出行数+1,然后进第二个递归

对于n很大的情况,由于k不大,所有只有当函数中的size很小的时候才有可能涉及到中间的printf和第二个递归

那么可以预处理出最大的满足第一个递归输出行数>=所求行数的size,然后从这里开始递归即可

代码:

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define LL long long
LL n,m;
LL pw2[];
void gkd(int x,char l,char md,char r){
if(pw2[x-]->=m) gkd(x-,l,r,md);
else if(pw2[x-]-==m-)
printf("move %d from %c to %c\n",x,l,md);
else{
m-=pw2[x-];
gkd(x-,r,md,l);
}
}
int main(){
//freopen("ddd.in","r",stdin);
pw2[]=;
for(int i=;i<;++i) pw2[i]=pw2[i-]*;
while(scanf("%lld%lld",&n,&m)!=EOF){
char l='A',md='B',r='C';
int tmp=;
for(;pw2[tmp]<=m;++tmp);
if((n-tmp)&) swap(md,r);
if(n<= && m>pw2[n]-) printf("Orz\n");
//注意n
else gkd(tmp,l,md,r);
}
return ;
}  

D. Director of Orz Pandas

题意:

给你两组物品,数量分别为n和m,每个物品有一个价值,还有k对关系,表示选了第一组的i物品就不能选第二组的j物品

现在问你可以取到的最大价值是多少

n,m<=100,k<=10000

可以把问题转化为先全部都选,然后剔除某些物品使得满足题目要求

裸的最小点权独立集,建图跑dinic即可,最坏复杂度O(n^2m)T不了

源到第一组的所有物品连边,权值为物品价值,第二组的所有物品到汇连边,权值为物品价值,冲突物品之间连无穷权值

鸽掉源或汇的一条边就表示剔除某个物品,只要有两个冲突的物品没被鸽掉就存在从源到汇的路径

所以最小鸽就是答案

代码:

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int rd(){int z=,mk=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')mk=-; ch=getchar();}
while(ch>=''&&ch<=''){z=(z<<)+(z<<)+ch-''; ch=getchar();}
return z*mk;
}
const int oo=;
struct edg{int y,nxt,v;}e[]; int lk[],ltp=;
void ist(int x,int y,int v){
e[++ltp]=(edg){y,lk[x],v}; lk[x]=ltp;
e[++ltp]=(edg){x,lk[y],}; lk[y]=ltp;
}
int n,m,o,a[]; int s,t;
int lvl[];
int q[],hd=;
int crt[];
bool gtlvl(){
for(int i=s;i<=t;++i) lvl[i]=;
lvl[(q[(hd=)]=s)]=;
for(int k=;k<=hd;++k){
crt[q[k]]=lk[q[k]];
for(int i=lk[q[k]];i;i=e[i].nxt)if(e[i].v && !lvl[e[i].y]){
lvl[e[i].y]=lvl[q[k]]+;
q[++hd]=e[i].y;
}
}
return lvl[t];
}
int mxflw(int x,int y){
if(x==t) return y;
int bwl=,flw=;
for(int i=crt[x];i && bwl<y;i=e[i].nxt)if(lvl[e[i].y]==lvl[x]+ && e[i].v)
if((flw=mxflw(e[i].y,min(e[i].v,y-bwl)))){
e[i].v-=flw,e[i^].v+=flw;
//cout<<e[i^1].y<<"->"<<e[i].y<<" "<<flw<<endl;
bwl+=flw;
if(!e[i].v) crt[x]=e[i].nxt;
}
if(!bwl) lvl[x]=;
return bwl;
}
int dnc(){
int bwl=,flw=;
while(gtlvl())while((flw=mxflw(s,oo))){
bwl+=flw;
//printf("%d %d\n",bwl,flw);
}
return bwl;
}
void prvs(){
ltp=;
for(int i=;i<=n+m+;++i) lk[i]=;
}
int main(){
//freopen("ddd.in","r",stdin);
while(scanf("%d%d",&n,&m)!=EOF){
prvs(); s=,t=n+m+;
int sm=;
for(int i=;i<=n;++i){
a[i]=rd();
sm+=a[i];
ist(s,i,a[i]);
}
for(int i=n+;i<=n+m;++i){
a[i]=rd();
sm+=a[i];
ist(i,t,a[i]);
}
o=rd();
int l,r;
while(o --> ){
l=rd(),r=rd();
if(l>r) swap(l,r);
ist(l,r,oo);
}
printf("%d\n",sm-dnc());
/*for(int i=s;i<=t;++i){
cout<<i<<":"<<endl;
for(int j=lk[i];j;j=e[j].nxt) printf("%d %d\n",e[j].y,e[j].v);
}*/
}
return ;
}  

H. Horton and Orz Pandas

题意:

给你一个n个点m条边的无向图,每条边都有两个权值a和b,现在问你在所有的包含所有点的联通子图中,a权值的和除以b权值的和的最大值是多少

n<=1000,m<=1e7

给a/b排序,然后Kruskal求最小生成树是错的

原因一,尽管有c/d<(a+c)/(b+d)<a/b当c/d<a/b的结论,但是

这也是最优比率生成树不能直接排序做的原因

原因二,答案不是最优比率生成树(即a权值的和除以b权值的和最大的生成树)

因为c/d<(a+c)/(b+d)<a/b,所以如果有树边的比率小于答案,那么把这条边加入是可以让答案增加的,而题中并没有规定一定要求生成树

本题实质上是求包含所有点的最大密度子图,是经典的01分数规划问题

令原图为S,λ=a(x)/b(x),其中a(x)表示子图x的a权之和,λ*=a(x*)/b(x*)为λ的最优值,则有0=a(x*)-λb(x*)

不妨设g(λ)=max{x⊆S | a(x)-λb(x)},则g(λ)是单调递减函数

证明:

对于λ1>λ2,g(λ1)=a(x1)-λ1b(x1) < a(x1)-λ2b(x1) (b(x)>0),而x1未必是λ2的最优解,即g(λ2)>=a(x1)-λ2b(x1)

故g(λ1)<=g(λ2)

又可以发现g(λ*)=0

证明:

若g(λ)=max{x⊆S | a(x)-λ*b(x)}>0,即∃x1使a(x1)-λ*b(x1)>0,则有λ*<a(x1)/b(x1),与λ*的定义不符

而根据定义,,∃x*使a(x1)-λ*b(x1)=0,故g(λ*)=0

那么只需二分答案,然后根据二分的答案构造新的边权a-bλ

此时原来的分数规划问题就转化为线性的问题,可以直接用Kruskal求最大生成树得到最优比率生成树

本题要求求包含所有点的最大密度子图

那么可以考虑对于只有一个边权的包含所有点的最大权值子图如何求

显然只需在最大生成树的基础上,把所有非负边权加入即可

那么对于构造出来的新边权做如上处理,检查答案是否大于零

本题注意:

1.浮点数二分不能(l+eps<r),会因为精度问题死循环,而应该计算好循环次数后直接for

2.因为sort次数很多,而结构体sort可能很慢,所以可以把结构体sort的比较函数的参数写成传地址形式,即参数名前加'&',或者手写排序

代码:

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<time.h>
using namespace std;
const double eps=1e-;
int rd(){int z=,mk=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') mk=-; ch=getchar();}
while(ch>=''&&ch<=''){z=(z<<)+(z<<)+ch-''; ch=getchar();}
return z*mk;
}
struct nds{int x,y,a,b; double c;}b[];
int n,m;
int tp[];
int gttp(int x){
int y=x,tmp;
while(tp[y]!=y) y=tp[y];
while(x!=y){
tmp=tp[x];
tp[x]=y;
x=tmp;
}
return y;
}
inline void mg(int x,int y){ tp[gttp(x)]=gttp(y);}
//用于求最优比率生成树的二分上下界
double gtmn(){
for(int i=;i<=n;++i) tp[i]=i;
double aa=,ab=;
for(int i=;i<=m;++i)if(gttp(b[i].x)!=gttp(b[i].y)){
mg(b[i].x,b[i].y);
aa+=b[i].a,ab+=b[i].b;
}
return ab/aa;
}
//bool cmp1(nds x,nds y){ return x.a<y.a;}
//bool cmp2(nds x,nds y){ return x.b>y.b;}
double gtmx(){
double aa=,ab=;
/*sort(b+1,b+m+1,cmp1);
for(int i=1;i<n;++i) aa+=b[i].a;
sort(b+1,b+m+1,cmp2);*/
for(int i=;i<n;++i) ab+=b[i].b;
//return ab/aa;
return ab;
}
int s; //用于检查运行时间
//手写堆排序
nds a[];
void st(){
for(int i=;i<=m;++i)
for(int j=i;j> && b[j].c<b[j>>].c;j>>=) swap(b[j],b[j>>]);
int sz=m;
for(int i=;i<=m;++i){
a[i]=b[];
swap(b[],b[sz--]);
for(int j=;j<=sz;){
int k=j;
if((j<<)<=sz && b[j<<].c<b[k].c) k=(j<<);
if((j<<|)<=sz && b[j<<|].c<b[k].c) k=(j<<|);
if(k==j) break;
swap(b[j],b[k]);
j=k;
}
}
for(int i=;i<=m;++i) b[i]=a[i];
}
bool cmp(nds &x,nds &y){ return x.c<y.c;} //使结构体sort加速
bool chck(double x){
for(int i=;i<=m;++i) b[i].c=b[i].b-x*b[i].a;
sort(b+,b+m+,cmp);
//st();
//cout<<clock()-s<<endl;
//s=clock();
double bwl=;
for(int i=;i<=n;++i) tp[i]=i;
for(int i=m;i>=;--i){
if(gttp(b[i].x)!=gttp(b[i].y)){
mg(b[i].x,b[i].y);
bwl+=b[i].c;
}
else if(b[i].c>) bwl+=b[i].c;
}
//cout<<clock()-s<<endl;
//s=clock();
return bwl>;
}
double bnrsch(){
double l=gtmn(),r=gtmx(),md;
//while(l+eps<r){ 注意浮点数二分的写法
int tmp=(log(r-l+)+*log())/log();
for(int i=;i<=tmp;++i){
md=(l+r)/;
(chck(md) ? l : r)=md;
//cout<<i<<" "<<clock()-s<<endl;
}
return chck(r) ? r : l;
}
int main(){
//freopen("ddd.in","r",stdin);
//s=clock();
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=;i<=m;++i) b[i].x=rd(),b[i].y=rd(),b[i].a=rd(),b[i].b=rd();
printf("%.10lf\n",bnrsch());
}
//cout<<clock()-s<<endl;
return ;
}

【Codeforces】Orz Panda Cup的更多相关文章

  1. 【Codeforces】Round #491 (Div. 2) 总结

    [Codeforces]Round #491 (Div. 2) 总结 这次尴尬了,D题fst,E没有做出来.... 不过还好,rating只掉了30,总体来说比较不稳,下次加油 A:If at fir ...

  2. 【Codeforces】Round #488 (Div. 2) 总结

    [Codeforces]Round #488 (Div. 2) 总结 比较僵硬的一场,还是手速不够,但是作为正式成为竞赛生的第一场比赛还是比较圆满的,起码没有FST,A掉ABCD,总排82,怒涨rat ...

  3. 2020-2021 “Orz Panda” Cup Programming Contest

    2020-2021 "Orz Panda" Cup Programming Contest 比赛情况 我们一共过了道3题 本场贡献:et3_tsy :过了A,提供了H的关键修改 ​ ...

  4. 【codeforces】【比赛题解】#931 CF Round #468 (Div. 2)

    因为太迟了,所以没去打. 后面打了Virtual Contest,没想到拿了个rank 3,如果E题更快还能再高,也是没什么想法. [A]Friends Meeting 题意: 在数轴上有两个整点\( ...

  5. 【CodeForces】601 D. Acyclic Organic Compounds

    [题目]D. Acyclic Organic Compounds [题意]给定一棵带点权树,每个点有一个字符,定义一个结点的字符串数为往下延伸能得到的不重复字符串数,求min(点权+字符串数),n&l ...

  6. 【Codeforces】849D. Rooter's Song

    [算法]模拟 [题意]http://codeforces.com/contest/849/problem/D 给定n个点从x轴或y轴的位置p时间t出发,相遇后按对方路径走,问每个数字撞到墙的位置.(还 ...

  7. 【CodeForces】983 E. NN country 树上倍增+二维数点

    [题目]E. NN country [题意]给定n个点的树和m条链,q次询问一条链(a,b)最少被多少条给定的链覆盖.\(n,m,q \leq 2*10^5\). [算法]树上倍增+二维数点(树状数组 ...

  8. 【CodeForces】925 C.Big Secret 异或

    [题目]C.Big Secret [题意]给定数组b,求重排列b数组使其前缀异或和数组a单调递增.\(n \leq 10^5,1 \leq b_i \leq 2^{60}\). [算法]异或 为了拆位 ...

  9. 【CodeForces】700 D. Huffman Coding on Segment 哈夫曼树+莫队+分块

    [题目]D. Huffman Coding on Segment [题意]给定n个数字,m次询问区间[l,r]的数字的哈夫曼编码总长.1<=n,m,ai<=10^5. [算法]哈夫曼树+莫 ...

随机推荐

  1. 记录下关于RabbitMQ常用知识点(持续更新)

    1.端口及说明: 4369 -- erlang发现口 5672 --client端通信口 15672 -- 管理界面ui端口 25672 -- server间内部通信口 举例说明 我们访问Rabbit ...

  2. NOIp2012:借教室

    题目描述 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海量租借教室的信息,我们自然 ...

  3. vue文字向上滚动

    <template> <vue-seamless-scroll :data="listData" :class-option="optionHover& ...

  4. idea开发shell脚本并运行

    参考:https://blog.csdn.net/u012443641/article/details/81295999 IEDA中的bashsupport插件支持在IDEA中编写shell脚本文件, ...

  5. shell 监控

    #!/bin/shsource /etc/profileserverName=$1dingDingName=$2 #获取内存情况memory=(`free | awk 'NR==2{print $2, ...

  6. leveldb单元测试之宏定义源码剖析

    前言 leveldb 是一个库,没有 main() 函数入口, 故非常难理清其中的代码逻辑.但好在库中有非常多的单元测试代码,帮助读者理解其中的各个模块的功能.然而,测试代码个人觉得一开始看时非常费解 ...

  7. [CF132C] Logo Turtle

    [CF132C] Logo Turtle , Luogu A turtle moves following by logos.(length is \(N\)) \(F\) means "m ...

  8. SQLite进阶-13.Autoincrement关键字

    目录 AUTOINCREMENT 是一个关键字,用于表中的字段值自动递增.我们可以在创建表时在特定的列名称上使用 AUTOINCREMENT 关键字实现该字段值的自动增加. 关键字 AUTOINCRE ...

  9. Dijkstra算法——超~~详细!!

    Dijkstra算法_ ** 时隔多月,我又回来了!**_ 今天下午久违的又学了会儿算法,又重新学习了一遍Dijkstra,这是第三次重新学习Dijkstra(*以前学的都忘完了>_<*) ...

  10. 【leetcode】74. 搜索二维矩阵

    题目链接:传送门 题目描述 编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值.该矩阵具有如下特性: 每行中的整数从左到右按升序排列. 每行的第一个整数大于前一行的最后一个整数. 示例  ...