【好词好段摘抄】【转载】

以下内容均为转载,侵删

1

  • 表示py是个很不错的语言
    对于IO密集型的应用,执行效率不再那么重要了
  • 程序大多数时间都在进行IO操作,而不是运算,实际效率也差不了太多
  • 举个栗子:
  • 常见的网络爬虫大多使用py编写。原因在于编码量小,并且有现成的库可以直接调用。并且由于带宽限制,打开网页的时间要远大于运算的时间。想象一下,打开一个网页需要1s的加载时间,py执行效率是cpp的1/10(标准状态),cpp渲染等操作需要0.01s,py需要0.1s,那么请你说一下0.2s打开一个网页与0.11s打开一个网页的差别。
    另外,py对正则表达式,多线程,多进程,协程兼容性远远好于cpp,用起来顺手。
  • 但是py也有不足,由于历史原因,编码问题一直是硬伤(不过貌似cpp也有wchar的问题)。
  • cyaron就是属于这种IO密集型的应用,没必要牺牲开发效率用执行效率高的cpp换取微不足道的性能提升.性能提升的瓶颈在于硬盘IO速度.与语言关系不大.优化方向应该在改进算法上.
  • 表示用了py3依旧经常被坑,果断换linux(或许是我太弱了?windows下经常爆炸)...

    2

    其实a+b是一个恒古不变的话题
    怎么证明1+1=2?

我们的计算机会给出一个完美的解答。
(我的解法在最后)

下面是A+B Problem题解综述

**【题目描述】
输入两个自然数,输出他们的和

【输入数据】
两个自然数x和y(0<=x,y<=32767)

【输出数据】
一个数,即x和y的和**

【思路】

【极简奢华派】

Free Pascal Code

var a,b:longint;
begin
    readln(a,b);
    writeln(a+b);
end.

C Code

#include <stdio.h>
int main()
{
    int a, b;
    scanf("%d%d", &a, &b);
    printf("%d\n", a + b);
    return 0;
}

C++ Code

#include <iostream>
using namespace std;
int main()
{
    int a, b;
    cin >> a >> b;
    cout << a + b << endl;
    return 0;
}

Python Code

print(sum(map(int, raw_input().split())))
Java Code
import java.io.*;
import java.util.Scanner;

public class Main {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        int b = sc.nextInt();
        System.out.println(a + b);
    }
}

【动态规划派】

此题考查动态规划思想首先我们需要把输入字符转换为数字a,b 然后使用动态规划求解A+B的值

最后输出答案我们可以设计出如下DP方程令f[j]表示i+j的值 则有f[0][0]=0 f[j]=max {f[i-1][j]+1, f[i][j-1]+1

由于对于每个i,j我们都要计算出f[j],因此时间复杂度与空间复O(n^2)

但是 对于题目提供的最大数字n=32767明显超时!

【优化1】

对于DP方程 由于每次计算只需要f[i-1][j]f[j-1]因此我们可以使用滚动数组优化DP的空间复杂度

使用两个整数x,y分别保存f[i-1][j]f[j-1]空间复杂度降为O(2) 然而时间复杂度O(n^2)仍然超时!
“时间复杂度,到目前为止还没有更好的优化方法。因此,此题被称为史上最难的dp??”

【优化2】

对于整数的运算 我们可以利用位运算的思想简化复杂度题目显然要我们求两非负整数之和。
我们知道,在非负整数加法的二进制逻辑运算中,每一位上的结果取决于以下两方面:
1、本位上两个逻辑位的异或值

2、后一位的结果是否溢出利用这种性质,可以考虑如下做法:令f[j]表示,考虑两个加数的后i、j位相加的结果,
显然有以下状态转移方程f[j]= max{f[i][j-1]+y & (1 << (j-)) f[i-1][j]+x & (1 << (i-1))

复制代码赋初值f[0][0]=(x & 1) ^ (y & 1)两个循环变量i,j从1循环到log(2,maxint)

我们成功的把时空复杂度降为O(log^2n)利用滚动数组,可以进一步降低复杂度为O(2)

至此,我们得到了一个较为圆满的解答

【题目评价】 此题实质上非常复杂 全面考察到了数学史和计算机史 经典代数 常用计算与输入输出
动态规划思想以及位运算思想等等等等知识点考虑到题目的所有可能性
我们应当从计算机存储的二进制的角度来逐步考虑数的表示 以字节计数,
采用多字节合用的方式表示一个大整数如今已经是高级程序语言编译器轻松可以达到的目标
可是为了加强对计算机计数的了解 此题可以考虑仍以最原始的方式进行计算
并且考虑最终将二进制数转变为十进制输出的全部过程
期间还考察了对ASCII码的熟悉程度然而此题在洛谷上的通过人数竟然高达23400人,通过率到达前所未有的57%!!!
可以看出洛谷上大神之多 不禁令人赞叹
【最小网络流派】

program problem;
var
en,et,ec,eu,ep,ex:Array[0..250000] of longint;
dis:array[0..1000] of longint;
v:array[0..1000] of boolean;
i,j,k,n,m,w,cost,l:longint;
a,b,ans,left,right:longint;function min(a,b:longint):longint;
begin
if a<b then
min:=a
else
min:=b
end;procedure addedge(s,t,c,u,k:longint);
begin
inc(l);
en[l]:=en[s];
en[s]:=l;
et[l]:=t;
ec[l]:=c;
eu[l]:=u;
ep[l]:=l+k;
end;procedure build(s,t,u,c:longint);
begin
addedge(s,t,c,u,1);
addedge(t,s,-c,0,-1);
end;
function aug(no,m:longint):longint;
var
i,d:longint;
begin
if no=n then
begin
inc(cost,m*dis[1]);
exit;
end;
v[no]:=true;
i:=ex[no];
while i<>0 do
begin
if (eu[i]>0) and not v[et[i]] and (dis[et[i]]+ec[i]=dis[no]) then
begin
d:=aug(et[i],min(m,eu[i]));
if d>0 then
begin
dec(eu[i],d);
inc(eu[ep[i]],d);
ex[no]:=i;
exit(d);
end;
end;
i:=en[i];
end;
ex[no]:=i;
exit(0);
end;function modlabel:boolean;
var
d,i,j:longint;
begin
d:=maxlongint;
for i:=1 to n do
if v[i] then
begin
j:=en[i];
while j<>0 do
begin
if (eu[j]>0) and not v[et[j]] and (ec[j]-dis[i]+dis[et[j]]<d) then
d:=ec[j]-dis[i]+dis[et[j]];
j:=en[j]
end;
end;
if d=maxlongint then exit(true);
for i:=1 to n do
if v[i] then
begin
v[i]:=false;
inc(dis[i],d);
end;
exit(false);
end;function work:longint;
var
i:longint;
begin
cost:=0;
repeat
for i:=1 to n do
ex[i]:=en[i];
while aug(1,maxlongint)>0 do
fillchar(v,sizeof(v),0);
until modlabel;
work:=cost;
end;
function solve(x,d:longint):longint;
var
i,k,t,p,last,cost,lk:longint;
begin
fillchar(en,sizeof(en),0);
fillchar(dis,sizeof(dis),0);
k:=0;
n:=2;
t:=x;
p:=0;
while x<>0 do
begin
k:=k+x mod 10;
x:=x div 10;
inc(p);
end;
n:=1;
x:=t;
l:=k+p+1;
last:=1;
cost:=1;
lk:=0;
while x<>0 do
begin
k:=x mod 10;
for i:=1 to k do
begin
inc(n);
build(last,n,1,-cost);
build(n,last+k+1,1,0);
end;
cost:=cost*10;
inc(n);
if last<>1 then
begin
if lk<k then
build(1,last,k-lk,0);
if k<lk then
build(last,n,lk-k,0);
end;
last:=n;
x:=x div 10;
if lk<k then
lk:=k;
end;
build(1,n,1,d);
solve:=-work;
end;begin
readln(a,b);
left:=1;
right:=1000000000;
while right-left>15000 do
begin
ans:=(left+right)shr 1;
if solve(ans,b)>a then
right:=ans
else
left:=ans;
end;
for i:=left to right do
if solve(i,b)=a then
begin
writeln(i);
halt;
end;
end.

【面向对象派】
还有一位用什么一个c++的面向对象的解法
走一波面向对象的A+B。

#include <bits/stdc++.h>

using namespace std;

class Something
{
friend istream & operator>>(istream & is, Something & as);
friend ostream & operator<<(ostream & os, Something & as);
public:
int a, b;
int sum(int x, int y);
Something & operator+(int z);
Something & operator+(Something b);

};

istream & operator>>(istream & is, Something & as)
{
is >> as.a;
return is;
}

ostream & operator<<(ostream & os, Something & as)
{
os << as.a;
return os;
}

int Something::sum(int x, int y)
{
return x + y;
}

Something & Something::operator+(int z)
{
a += z;
return this;
}

Something & Something::operator+(Something b)
{
a += b.a;
return this;
}

int main(int argc, char const *argv[])
{
Something sd, st;
cin >> sd >> st;
cout << sd + st;
return 0;
}

【树派】
最小生成树最好了

include <cstdio> 
include <algorithm> define INF 2140000000
using namespace std;
struct tree{int x,y,t;}a[10];
bool cmp(const tree&a,const tree&b){return a.t<b.t;}
int f[11],i,j,k,n,m,x,y,t,ans;
int root(int x){if (f[x]==x) return x;f[x]=root(f[x]);return f[x];}
int main(){
for (i=1;i<=10;i++) f[i]=i;
for (i=1;i<=2;i++){
scanf("%d",&a[i].t);
a[i].x=i+1;a[i].y=1;k++;
}
a[++k].x=1;a[k].y=3,a[k].t=INF;
sort(a+1,a+1+k,cmp);
for (i=1;i<=k;i++){
// printf("%d %d %d %d\n",k,a[i].x,a[i].y,a[i].t);
x=root(a[i].x);y=root(a[i].y);
if (x!=y) f[x]=y,ans+=a[i].t;
}
printf("%d\n",ans);
}

线段树走起
附上在下65行线段树代码

include<cstdio> include<algorithm> include<cstdlib> include<cmath> include<cstring> include<iostream>
using namespace std;
struct node{
int val,l,r;
};
node t[5];
int a[5],f[5];
int n,m;
void init(){
for(int i=1;i<=2;i++){
scanf("%d",&a[i]);
}
}
void build(int l,int r,int node){//这是棵树
t[node].l=l;t[node].r=r;t[node].val=0;
if(l==r){
f[l]=node;
t[node].val=a[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,node2);
build(mid+1,r,node2+1);
t[node].val=t[node2].val+t[node2+1].val;
}
void update(int node){
if(node==1)return;
int fa=node>>1;
t[fa].val=t[fa2].val+t[fa2+1].val;
update(fa);
}
int find(int l,int r,int node){
if(t[node].l==l&&t[node].r==r){
return t[node].val;
}
int sum=0;
int lc=node*2;int rc=lc+1;
if(t[lc].r>=l){
if(t[lc].r>=r){
sum+=find(l,r,lc);
}
else{
sum+=find(l,t[lc].r,lc);
}
}
if(t[rc].l<=r){
if(t[rc].l<=l){
sum+=find(l,r,rc);
}
else{
sum+=find(t[rc].l,r,rc);
}
}
return sum;
}
int main(){
init();
build(1,2,1);
printf("%d",find(1,2,1));
}

各位大神都用网络流啊 最短路啊解这道题,那么既然是可以求最短路,为什么不可以从树上跑呢?
怀着这种想法,我冥思苦想(划掉),发现,###我可以用LCA做这道题啊~
然而鄙人不才,什么Tarjan啊ST表啊都不会,只会用一个倍增来求LCA,所以权当抛砖引玉吧。
不过我估计应该没什么想学LCA的来这道题看LCA题解吧。所以多半是写着玩~~
先说说思路(这还用说?):
建一个有三个节点的树,1为树根,2 3分别是左右儿子。
其中1 2之间的距离为a,2 3之间的距离为b,然后求1 2的LCA,和分别到LCA的距离,加起来就是1->3的最短路
其实就是题目中所求的a+b了
好吧闲话不说 上代码了(多半是个LCA的板子了):

include<cstdio> //头文件 define NI 2
//从来不喜欢算log所以一般用常数 不知道算不算坏习惯 因为3个节点 所以log3(当然以2为底)上取整得2
struct edge
{
int to,next,data; //分别表示边的终点,下一条边的编号和边的权值
}e[30]; //邻接表,点少边少开30是为了浪啊
int v[10],d[10],lca[10][NI+1],f[10][NI+1],tot=0; //数组开到10依然为了浪
//数组还解释嘛,v表示第一条边在邻接表中的编号,d是深度,lca[x][i]表示x向上跳2^i的节点,f[x][i]表示x向上跳2^i的距离和
void build(int x,int y,int z) //建边
{
e[++tot].to=y; e[tot].data=z; e[tot].next=v[x]; v[x]=tot;
e[++tot].to=x; e[tot].data=z; e[tot].next=v[y]; v[y]=tot;
}
void dfs(int x) //递归建树
{
for(int i=1;i<=NI;i++) //懒,所以常数懒得优化
f[x][i]=f[x][i-1]+f[lca[x][i-1]][i-1],
lca[x][i]=lca[lca[x][i-1]][i-1]; //建树的同时进行预处理
for(int i=v[x];i;i=e[i].next) //遍历每个连接的点
{
int y=e[i].to;
if(lca[x][0]==y) continue;
lca[y][0]=x; //小技巧:lca[x][0]即为x的父亲~~(向上跳2^0=1不就是父节点嘛)
f[y][0]=e[i].data;
d[y]=d[x]+1;
dfs(y); //再以这个节点为根建子树【这里真的用得到嘛??】
}
}
int ask(int x,int y) //询问,也是关键
{
if(d[x]<d[y]) {int t=x;x=y;y=t;} //把x搞成深的点 int k=d[x]-d[y],ans=0; for(int i=0;i<=NI;i++) if(k&(1<<i)) //若能跳就把x跳一跳 ans+=f[x][i], //更新信息 x=lca[x][i]; for(int i=NI;i>=0;i--) //不知道能不能正着循环,好像倒着优,反正记得倒着就好了
if(lca[x][i]!=lca[y][i]) //如果x跳2^i和y跳2^j没跳到一起就让他们跳
ans+=f[x][i]+f[y][i],
x=lca[x][i],y=lca[y][i];
return ans+f[x][0]+f[y][0]; //跳到LCA上去(每步跳的时候都要更新信息,而且要在跳之前更新信息哦~)
}
int main()
{
int a,b;
scanf("%d%d",&a,&b);
build(1,2,a);
build(1,3,b); //分别建1 2、1 3之间的边
dfs(1); //以1为根建树
printf("%d",ask(2,3)); //求解2 3到它们的LCA的距离和并输出
}

【我的解法】【图派】
对此,我就笑笑:
当然,这么经典的一道图论题怎么能错过呢?
这道题实际上是一道最短路的模型题。我们只需要构造一个有三个顶点的无向图,1和2之间有一条边权为a的边,2和3之间有一条边权为b的边,而1和3之间有一条边权为maxlongint的边,那么答案就是1到3的最短路
代码如下:

var a,b,i,j,k,n:longint;
    g:array[1..10000,1..10000]of longint;
begin
 readln(a,b);
 g[1,2]:=a;
 g[2,1]:=a;
 g[2,3]:=b;
 g[3,2]:=b;
 n:=3;
 for i:=1 to n do
  for j:=1 to n do
   if g[i,j]=0 then g[i,j]:=maxlongint div 2;
 for k:=1 to n do
  for i:=1 to n do
   for j:=1 to n do
    if (i<>j)and(j<>k)and(k<>i)and(g[i,j]>g[i,k]+g[k,j])
    then g[i,j]:=g[i,k]+g[k,j];
 writeln(g[1,n]);
end.
O(n^2)dijkstra算法
const maxn=3;
      longlong=maxlongint div 3;
var n,m,s,i,j,ans,x,y,z,aa,bb:longint;
    g:array[0..3,0..3]of longint;
    d:array[0..3]of longint;
function min(a,b:longint):longint;
begin
 if a>b then exit(b) else exit(a);
end;
procedure dijkstra(v0:longint);
var i,j,k,minn:longint;
    u:array[1..maxn]of boolean;
begin
 fillchar(u,sizeof(u),false);
 for i:=1 to n do d[i]:=g[v0,i];
 u[v0]:=true;
 for i:=1 to n-1 do begin
  minn:=longlong; k:=0;
  for j:=1 to n do
   if (not u[j])and(d[j]<minn) then begin
    minn:=d[j]; k:=j;
   end;
  if k=0 then break;
  u[k]:=true;
  for j:=1 to n do
   if (not u[j])and(d[j]>g[k,j]+d[k])then
    d[j]:=g[k,j]+d[k];
 end;
end;
BEGIN
 readln(aa,bb);
 g[1,2]:=aa;
 g[2,1]:=aa;
 g[2,3]:=bb;
 g[3,2]:=bb;
 n:=3;
 m:=3;
 g[1,3]:=longlong;
 g[3,1]:=longlong;
 fillchar(d,sizeof(d),$7f);
 dijkstra(1);
 writeln(d[n]);
END.

表示会不定期更新,勿喷

转载于:https://www.cnblogs.com/zhcs/p/7090246.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值