Statistic Learning Study

TM
trade mark 商标

Decision Tree

属于判别模型,目标函数是最小正则化的极大似然估计,

Caplat(T)= C(T)+alpha |T|

右侧惩罚项,表示模型复杂度,也即叶子节点个数,前面的训练误差,后面是模型复杂度,如果没有后面的正则项的话,容易过拟合,因此

算法采用ID3和C4.5, 每次进行信息增益比最大的特征选择。

中缀表达式算法已经忘得一干二净了。。。

定义运算符优先级,其中)( 与 #) 与 (# 对于合法的表达式都是不会出现的。

op stack push '#'
while(s[i]!='#' || stop.top()!='#')
{
    if( 0-9)
    {
        get continuous dig and push to num stack
    }
    else
    {
        char c=op stack top, cur=s[i]
        if(c<cur) op stack push cur, i++
        else if(c==cur) op pop //'9' ')'
        else
        {
            num2=num stack pop
            num1=num stack pop
            op=op stack op
            num stack push (num1 op num2)
            //notice this do not i++, as cur op should process all pre op that is lower than it
        }
    }
}
return num stack top

https://leetcode.com/problems/basic-calculator/
代码如下:

class Solution {
public:
    string Pri[5]={"=<<<?",
    ">>><>",
    ">>><>",
    "?<<<=",
    ">>>?>"};
    int index(char op)
    {
        if(op=='#') return 0;
        else if(op=='+') return 1;
        else if(op=='-') return 2;
        else if(op=='(') return 3;
        else return 4;
    }
    int calculate(string s)
    {
        s.push_back('#');
        int n=s.size();
        stack<int> stnum;
        stack<char> stop;
        stop.push('#');
        int i=0;
        while(i<n && (s[i]!='#' || stop.top()!='#'))
        {
            while(i<n && s[i]==' ') i++;
            if(i==n) break;
            if(isdigit(s[i]))
            {
                int si=i++;
                while(i<n && isdigit(s[i])) i++;
                stnum.push(stoi(s.substr(si, i-si)));
            }
            else
            {
                char etop=stop.top(), ecur=s[i];
                char pri=Pri[index(etop)][index(ecur)];
                if(pri=='<')
                {
                    stop.push(ecur);
                    i++;
                }
                else if(pri=='=')
                {
                    stop.pop();
                    i++;
                }
                else
                {
                    int num2=stnum.top();stnum.pop();
                    int num1=stnum.top();stnum.pop();
                    char e=stop.top(); stop.pop();
                    int ans= ( (e=='+') ? (num1+num2) : (num1-num2));
                    stnum.push(ans);
                }
            }
        }
        //cout<<stnum.size()<<endl;
        return stnum.top();
    }
} S;

Posted by richard爱闹 - 6月 9 2015
如需转载,请注明: 本文来自 Richard

Binary Search

非常好的博客, http://www.hawstein.com/posts/make-thiner-programming-pearls.html
教你快速读完编程珠玑

round函数 是四舍五入,靠近最近的整数

二分查找专题,瞿神推荐

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=80425#overview

题目B,对于给定数组的m划分,使得每个划分的累加和最大值最小

这里又想了一个计数问题,n个数m划分(要求连续的数划分在一起),每个至少为1,那么一共多少种。

我进入算法思维,首选dp,对于最后一个元素,所在集合有1个或多个数,因此枚举
dp(n, m)=sum(dp(n-lastsize, m-1)) lastsize=1->n-(m-1)

应该是可以算的。

然而这其实就是一个插板法,n-1块地方放m-1块板,C(n-1,m-1)

言归正传。二分可以考虑二分答案,这是常见思路。对于mid,我们尝试划分
n个数,使得每个区间sum<=mid, 看最后能不能划分m个区间,如果<=m个,说明我们的mid选大了,如果选小一点,区间数可以多一些,以达到刚好m个,但是mid还是要保留,high=mid, 否则low=mid+1.
二分下届是max(ai), 上届是sum(ai)

bool judge(LL mid)
{
    LL sum=0, cnt=0;;
    for(LL i=0;i<n;i++)
    {
        sum+=a[i];
        if(sum>mid)
        {
            cnt++;
            i--;
            sum=0;
        }
    }
    cnt++;
    return cnt<=m;
}
int main()
{
/*
#ifndef ONLINE_JUDGE
    freopen ("in.txt" , "r" , stdin);
    freopen ("out.txt" , "w" , stdout);
#endif
*/
    while(cin>>n>>m)
    {
        LL sum =0, maxx=-1;
        for(LL i=0;i<n;i++) cin>>a[i], sum+=a[i] ,maxx=max(maxx, a[i]);
        LL low=maxx, high=sum;
        while(low<high)
        {
            LL mid=(low+high)/2;
            if(judge(mid)) high=mid;
            else low=mid+1;
        }
        cout<<low<<endl;
    }
    return 0;
}

另一道更偏数值计算,感觉二分的算法很多是数值计算的内容
里面有一个性质一直没懂
题目E,是01分数规划

max(sum(aixi)/sum(bixi)) st: sum(xi)=n-k, xi=0|1

这个最大值等价于
f(L)=sum(aixi)-L*sum(bixi)

但是具体为何还不清楚。知道这个之后,就是算最大的n-k个ai-mid*bi, 然后
按照这个来二分

double epsilon=1e-7;
while(~scanf("%d%d", &n, &k))
{
    if(!n && !k) break;
    for(int i=0;i<n;i++) a[i]=getint();
    for(int i=0;i<n;i++) b[i]=getint();
    double low=0, high=1;
    while(high-low>=epsilon)
    {
        double mid=(low+high)/2;
        for(int i=0;i<n;i++) t[i]=a[i]-mid*b[i];
        sort(t, t+n);
        double f=0;
        for(int i=k;i<n;i++) f+=t[i];
        if(f>=0) low=mid;
        else high=mid;
    }
    cout<<(round)(low*100)<<endl;
}

Posted by richard爱闹 - 6月 9 2015
如需转载,请注明: 本文来自 Richard

large data process

astounding 令人震惊的
budget 预算
fiscal 财政的

python 一句话搞定 reversestring

著名面试题,单词之间顺序reverse,本身不变
return ‘ ‘.join([word[::-1] for word in s[::-1].split()])

python 的代码真是写的可以短到不能再短了

  1. 支持多个变量一行同时赋值
    i, j=i+1, j+1
  2. 虽然没有引用传递,但是参数返回个数可变,多个返回是非常方便的
    h, isBBT=self.B(root)

附上判断一颗树是否BBT的python代码

真是pythonic啊!

class Solution:
    # @param {TreeNode} root
    # @return {boolean}
    def isBalanced(self, root):
        h, isBBT=self.B(root)
        return isBBT

    def B(self, root):
        if root is None:
            return 0, True
        lh, Left=self.B(root.left)
        rh, Right=self.B(root.right)
        h=max(lh, rh)+1
        return h, Left and Right and abs(rh-lh)<=1

海量数据处理往往有几种思路。

多半是数据量太大,内存放不下,优化空间

一种是bitmap,来优化,判重是可以用BloomFilter,该方法非常牛,
在BigTable,QQmail spamemail 判重等领域都广泛运用,因为全世界的垃圾邮件域名在一直增长。

题目是给定10^7个-10^7~10^7范围的数,文件里面,给定1MB内存,要求进行排序,存回文件。

题目说的是7位整数,但如果非负的话,范围应该是10^8了。

用bitmap的话,10^7/8=1.25MB,因此解决方案是把整数划分为两段,然后每一段分别做一次基于bitmap的排序,然后两个文件分别归并依次就好了。

编程珠玑第二炮,40亿个32位整数找一个不在里面的数。

1) 内存1G
2) 内存10MB,有一些外存

第一个,bitmap空间, bitmap切记与数据范围有关,2^32/8/1024/1024/1024=0.5GB, 直接bitmap建立,然后扫一遍第一个为0的就是了。

第二个分块,1000大小例如,0-999在block0,1000-1999在block1,
对于那些块的计数器<1000的一定有不存在的数,(>=1000的只是可能有,但是<1000的是一定有),然后读取所有数,在这块里面的第一次0的就是目标值

今天看到知乎黑July的,kmp微博转三次。哈哈哈

于是我打算再写一遍KMP

void GetNext(string pat)
{
    int n=pat.size();
    Next[0]=-1;
    for(int i=0;i<=n-2;i++)
    {
        int k=Next[i];
        while(k!=-1 && pat[k]!=pat[i])
            k=Next[k];
        Next[i+1]=k+1;
    }
}

int KMP(string str, string pat)
{
    GetNext(pat);
    int m=str.size(), n=pat.size();
    int i=0, j=0;
    while(i<m && j<n)
    {
        if(j==-1 || str[i]==pat[j])
            i++, j++;
        else
            j=Next[j];
        if(j==n)
            return i-j;
    }
    return -1;
}

Python版的,主要是想试试Python在字符串处理的优势

__author__ = 'richard'


def GetNext(pat, Next):
    n=len(pat)
    Next[0]=-1
    for i in range(n-1):
        k=Next[i]
        while k!=-1 and pat[k]!=pat[i]:
            k=Next[k]
        Next[i+1]=k+1

def KMP(str, pat):
    Next=[0]*len(pat)
    GetNext(pat, Next)
    m, n, i, j=len(str), len(pat), 0, 0
    while i<m and j<n:
        if j==-1 or str[i]==pat[j]:
            i, j=i+1, j+1
        else:
            j=Next[j]
        if j==n:
            return i-j
    return -1

str='zhangruichang'
pat='chang'
print KMP(str,pat)

bloomfilter是压缩空间的优良去重数据结构,但是有一定的错误率,也就是
会把可能不属于集合里的认为是集合里的。

因此这个作为垃圾邮件的判重器会有比较大的代价,因为把一个好邮件判为
垃圾邮件代价是非常大的,解决方法好像是建立一个白名单,但是具体怎么弄的还不是很清楚

Posted by richard爱闹 - 6月 8 2015
如需转载,请注明: 本文来自 Richard

BC43ProB

python cmath 是复数的sqrt,因此返回的是复数

问题2:

描述:

n张卡片摆成一排,分别为第1张到第n张,开始时它们都是下面朝下的。你有两种操作:

T(i,j):将第i张到第j张卡片进行翻转,包含i和j这两张。(正面变反面,反面变正面)
Q(i):如果第i张卡片正面朝下,返回0;否则返回1.

对于每个query,操作1是ON的操作2是O1的因此m次query最坏O(mn)

现在采用树状数组,可以使得每个query都是logn, 以此降低总的时间为O(mlogn)

http://www.hawstein.com/posts/binary-indexed-trees.html#change

python 输入两个int变量怎么弄

var1, var2 = [int(x) for x in raw_input(“Enter two numbers here: “).split()]

python打印浮点数,不要加float(),否则又会按照float的定义,打印一位小数

print 0.00
它也会先转成float然后按照0.0打印,因此一定要
print (“%.2f” % 0)

第一次听《烟花易冷》,感觉作曲不太圆润,没有看歌词,有点飘忽不定。但是鉴于以往,JAY的很多歌都是渐入型的,就是第一次听没感觉,越听越会陷进去,譬如“以父之名”“夜曲”之类,于是多听几次试试。
调出了歌词,以卡拉OK模式走动,伴曲轻扬,听着听着,有点孤独的感觉,像是走进了《诛仙》,不知道大家看过诛仙没有,个人认为是目前最好看的小说之一。像书中男主角小凡,孤单落寞,跪在雨中,无人问津的情形。

再听几遍,加上反复领略歌词意境,“雨纷纷,旧故里草木深;我听闻,你始终一个人 ”“城郊牧笛声,落在那座野村;缘份落地生根是,我们”发现之前认为的曲调多拐一点都不存在了,反而是抑扬之间渗出了几丝佛韵,让人心静止水,遁入空门..方文山文雅,含蓄的淡淡几个字却写出山水长天无穷幻化的意境,着实佩服!

整夜调成单曲循环,伴曲入睡,半夜里泪流满面,感觉到五脏六腑的翻滚,多情伤离别,冷落清秋节..
传说中有首歌叫“黑色星期五”说是听了的人多会抑郁,产生轻生之念,后因全球多人听此歌自杀,遍成了全球禁歌。

今次听周杰伦新歌《烟花易冷》,我不敢保证这首歌会不会像“东风破”,“青花瓷”一般成为老少皆宜引领流行乐坛走势的中国风潮曲,但是字曲间流露出的伤感和淡薄却足以让人脱凡离尘,隐约有种出家的冲动。是为神曲!

不知道各位亲友听了之后有没有同感,小弟大胆预言:周杰伦这首最新的单曲《烟花易冷》很可能因引发佛门大盛而成为全球禁歌!

一篇不错的 帖子
http://machinelearningmastery.com/building-a-production-machine-learning-infrastructure/
自己想成为的方向,但是还差的很多

http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=599&pid=1002

今晚BC第二题是一道非常有趣的算法题。

给定一个数组和p,求max(i!=j) (a[i]+a[j])%p

n=10^5 初看是n^2的搜索空间,似乎有nlogn算法,于是朝二分靠
但是发现没有二分的性质,因为一个点定下来,后面的点和这个点的和不是单调的,因此没有二分砍的条件。

后来问了bin神,大概是我的级别不够,没有完全理解。

随后我想了一下,全部取模之后就是两类了,一类是twosum<p, 一类是p<=twosum<2p-1

因此我就对于一个点,先二分出第一次和>=p的,然后第一类max就是前一点,第二类max就是最后一点,二分上届是i+1,下界是n-1

while(~scanf("%lld%lld", &n, &p))
{
    for(int i=0;i<n;i++) scanf("%d", &a[i]), a[i]%=p;
    sort(a, a+n);
    LL ans=(a[0]+a[1])%p;
    for(int i=0;i<n-1;i++)
    {
        int low=i+1,high=n-1;
        while(low<high)
        {
            int mid=(low+high)/2;
            if(a[mid]+a[i]>=p) high=mid;
            else low=mid+1;
        }
        //low
        ans=max(max(ans, (a[i]+a[low-1])%p), (a[i]+a[n-1])%p);
    }
    printf("%lld\n", ans);
}

后来看了题解,第二步处理可以on搞定。
因为最大两个数一定是第二类max,现在找第一类max,如果小的从小到大枚举,
那么大的一定是从大到小枚举,双指针算法需要满足这个性质。

之前很多双指针的算法一直不明白什么时候可以用
比如right找到了sum<=p的最大值,那么right不可能再往后面,因为前面会大,
所以right不需要回溯的,前面同理。

所以是ON的一个扫描

while(~scanf("%lld%lld", &n, &p))
{
    for(int i=0;i<n;i++) scanf("%lld", &a[i]), a[i]=a[i]%p;
    sort(a, a+n);
    LL ans=(a[n-2]+a[n-1])%p;
    int i=0, j=n-1;
    //while(a[i]+a[j]>=p) j--;
    while(i<j)
    {
        while(i<j && a[i]+a[j]>=p) j--;
        if(i<j) ans=max(ans, (a[i]+a[j])%p);
        i++;
        while(i<j && a[i]+a[j]<p) i++;
        if(i-1<j) ans=max(ans, (a[i-1]+a[j])%p);
        j--;
    }
    printf("%lld\n", ans);//<<endl;
}

Posted by richard爱闹 - 6月 7 2015
如需转载,请注明: 本文来自 Richard

DZY loves balls combination dp

python 如何 按照 数组个数打印list的元素

L=[1,2,3,4,5]
print ‘ ‘.join([str(i) for i in L])
join 需要是存string的list也即每个join对象是string

[1,2,3,4,5] -> [‘1’, ‘2’, ‘3’, ‘4’, ‘5’]
一句话将一个list的里面每个元素都进行转化 [str(i) for i in L]

latex
公式自动换行,但是还是一个公式用split,然后里面\

\begin{equation}\label{eq:28}
\begin{split}
    h_{0}\sim P(h|v_{0})\\
    v_{1}\sim P(v|h_{0})\\
    h_{1}\sim P(h|v_{1})\\
    v_{2}\sim P(v|h_{1})\\
    h_{l}\sim P(h|v_{l})\\
    v_{l+1}\sim P(v|h_{l})
\end{split}
\end{equation}

今天做了一题,对于被8整除的数,性质就是最后三位被8整除。

之前只知道被2整除看各位,被3整除看数字和是否被3整除

知道这个性质之后可以n^3的暴力写CF306Div2ProC了

http://acm.hdu.edu.cn/showproblem.php?pid=5194

BC35ProA的一题

当年由于数据小打表过的。昨天蛋哥提到了一道他本科离散数学的一道题,于是我想到了这题

然后想了一下DP的思考过程。哎,大神们都是直接给出DP方程,却把最重要的思维过程,毕竟谁都是曾经弱过的啊,一开始不可能一下就想到了定义dp状态,除非看答案。

首选是直接按照问题来定义dp,dpij表示i个1,j个0的所有排列中’01’的个数
然后看dp-1j, dpij-1, dpi-1j-1, 一般都是看这几个

如果抽象思维不够快,可以举小数据的例子,例如n=2,m=2
一举例发现特别快,就是最后一位是0,那么就是dpij-1, 最后一位是1就是dpi-1j, 然后还有倒数第二个是0和最后1组成的,也就是n-2个1 m-2个0里面的组合数,C(n+m-2, n-1)

因此dp[i][j]=dp[i][j-1]+dp[i-1][j]+C(n+m-2, n-1)

对于初始条件,二维的最好方法就是写个二维表格,然后看0行0列举例

n<1 || m<1时,肯定是0个了,所以全是0

另外算组合数要用Cij=Ci-1j-1+Ci-1j这个公式

因为直接算可能分子分母会上溢出,这是和数学的本质区别,算法强调计算性。

int C[30][30], dp[30][30];
void Calc()
{
    memset(C, 0, sizeof C);
    for(int i=0;i<=24;i++) C[i][0]=1;
    for(int i=1;i<=24;i++) for(int j=1;j<=24;j++)
        C[i][j]=C[i-1][j-1]+C[i-1][j];
}
int main()
{
/*
#ifndef ONLINE_JUDGE
    freopen ("in.txt" , "r" , stdin);
    freopen ("out.txt" , "w" , stdout);
#endif
*/
    Calc();
    while(cin>>n>>m)
    {
        memset(dp, 0 ,sizeof dp);
        for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
            dp[i][j]=dp[i][j-1]+dp[i-1][j]+C[i+j-2][i-1];
        int gcd=GCD(dp[n][m], C[n+m][n]);
        cout<<dp[n][m]/gcd<<'/'<<C[n+m][n]/gcd<<endl;
    }
    return 0;
}

另外再附上一题,长为n的01序列里’01’出现的次数

dpi=2*dpi-1+2^(i-2)
参数为1个的话,更加好思考,

分成两块,一块是完全由n-1长串里01的个数决定,最后一位0或1,2*dpn-1
一块是由n-1长串和第n个共同贡献的01, 也即最后两位是01, 也即n-2长串的组合数2^(n-2)

再用plug-in方法直接算通项 dpn=(n-1)*2^(n-2)

Posted by richard爱闹 - 6月 5 2015
如需转载,请注明: 本文来自 Richard

SQL review

python需要把空格去掉,不然读取一行raw_input()就会出问题
我还以为是2.7.4和2.7.6的差别呢。

versatile: 全能的
pessimistic: 悲观的
optimistic: 乐观的
Marbles:大理石
falsity: 错误
理解loop invariant的好turorial, mark
http://www.cs.uofs.edu/~mccloske/courses/cmps144/invariants_lec.html

https://leetcode.com/problems/department-highest-salary/

select D.Name, E.Name, D.Salary
from Employee E
(select DepartmentId, Max(Employee.Salary) MS
from Department
group by Name) T,
Department D
where E.DepartmentId=T.DepartmentId
and E.DepartmentId=D.Id
and E.Salary=T.MS

Write your MySQL query statement below
找到连续的出现至少三次的数
select distinct l1.num
from Logs as l1, Logs as l2, Logs as l3
where l3.id-l2.id=1
and l2.id-l1.id=1
and l1.num=l2.num
and l2.num=l3.num;

https://leetcode.com/problems/rising-temperature/

好久没写SQL了,都快不会写了。

这题两个表Join,区分名字用Weather as w1,

https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_datediff 官方文档

DATEDIFF(DATE d1, DATE d2)
表示d1-d2的天数

然后注意一下温度的差别就好了

这题居然遇到了Internal Error 第一次遇到= =

# Write your MySQL query statement below
select w2.id 
from Weather as w1, Weather as w2
where DATEDIFF(w2.Date, w1.Date)=1
and w1.Temperature<w2.Temperature;

Posted by richard爱闹 - 6月 3 2015
如需转载,请注明: 本文来自 Richard

Gas Station

Kmeans 算法和EM有点相似,从蛋哥学习的。

一日不学,如隔千秋啊!最近正逢开学,一直都没有看过书。今天想着做几道进制转换的题。算完之后,本想用python检验一下的,没想到竟然忘掉怎么转换的了(话说平时也基本不怎么用到进制转换)。果断翻书去查,哪知翻来翻去,硬是没找到(当初学的时候也是想着暂时用不着,就没怎么看过),最后只好向度娘求救。为了记住这一次的教训,也算是整理一下笔记,特地写此文章作为记录。

十进制转换二进制

bin(10)
‘0b1010’

十进制转换十六进制

hex(10)
‘0xa’

二进制转换十进制

int(‘1010’,2)
10

十六进制转换十进制

int(‘0xa’,16)
10

十六进制转换二进制

bin(0xa)
‘0b1010’

二进制转换十六进制

hex(0b1010)
‘0xa’

python 没有实现链表

http://blog.suchasplus.com/2011/03/why-python-Standard-library-does-not-implement-the-list.html

python即是属于非常简洁完美的语言。没有C++那么多冗余的stack queue啥的
因为数组写成栈非常简单。

python 常用数据结构list, 顺序表
sets hash表
dictionary hashmap

myds=[]//list
myds=sets()//sets, hashset
myds={}//dictionary, hashmap
myds=()//tuple

toposort dfs版from 学神

拓扑其实dfs bfs都可以,但是都是基于临界点并且入度为0的来扩展,
其实本质没区别,之前看的geeksforgeeks那个实在有点蹩脚,直接弃掉了,还用了栈,哎

int deg[maxn], n, t, m, tt=0, x, y;
vector<int> edge[maxn];

void dfs(int i)
{
    deg[i]=-1;//visit mark
    tt++;
    for(auto e: edge[i])
    {
        if(--deg[e]==0) dfs(e);
    }
}
int main()
{
/*
#ifndef ONLINE_JUDGE
    freopen ("in.txt" , "r" , stdin);
    freopen ("out.txt" , "w" , stdout);
#endif
*/
    cin>>t;
    for(int ti=1;ti<=t;ti++)
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++) edge[i].clear(), deg[i]=0;
        for(int i=0;i<m;i++)
        {
            cin>>x>>y;
            edge[x].push_back(y);
            deg[y]++;
        }
        tt=0;
        for(int i=1;i<=n;i++)
        {
            if(!deg[i]) dfs(i);
        }
        puts(tt==n ? "Correct": "Wrong");
    }
    return 0;
}

Java 的数组全都是new的,而且初始为0,C++的局部自动变量的数组都是野值,需要初始化,非常麻烦。

3、continuous是指时间/过程上的“继续”和“承接”,强调中间的“内容或实体”不发生中断或缺失(但是在时间/过程上可以暂时中止/停顿,后续承接着往下发展),是在原有状态下的“继起”和“延续”。如电视连续剧是指在剧情上承接,但可以中途停播然后续播,文章或故事也先写一部分再于后面其它时间续完(这时候最先的文章末尾常有to be continued 或 to be completed字样)。
4、contiguous跟continuous只有g和n一个字母的差别,但它们的区别还是很明显的。contiguous是指地域上的相连、相邻、交界,是“毗邻”的意思,如广东和广西在地域上就是contiguous的,Excel中的单元格之间也是contiguous的。

简单的说,continuous是指时间上的连续,或者过程的连续,
contiguous是指空间的连续

largest rectangle
维护一个单调递增的队列,用栈来存。
左到右是递增,右到左算也是递增的。
代码模板来自谢老师,谢老师分分钟教我单调队列入门~~~

class Solution {
public:
    int largestRectangleArea(vector<int>& h) {
        int n=h.size();
        int l[n], r[n];
        stack<int> s1;//mono increase queue
        for(int i=0;i<n;)
        {
            if(s1.empty())
            {
                l[i]=i;
                s1.push(i++);
            }
            else if(h[s1.top()]<h[i])
            {
                l[i]=i-s1.top()-1;
                s1.push(i++);
            }
            else s1.pop();
        }
        stack<int> s2;//mono increase queue
        for(int i=n-1;i>=0;)
        {
            if(s2.empty())
            {
                r[i]=n-1-i;
                s2.push(i--);
            }
            else if(h[s2.top()]<h[i])
            {
                r[i]=s2.top()-i-1;
                s2.push(i--);
            }
            else s2.pop();
        }
        int ans=0;
        for(int i=0;i<n;i++)
            ans=max(ans, h[i]*(l[i]+r[i]+1));
        return ans;
    }
} S;

这道题目就是找一个起点,使得每一次累加gas 和 cost 差值之后一直为正。

分析了两个性质之后,就可以解题了。

  1. 如果sum gas>= sum cost, 那么一定有解.
  2. 如果从某个起点start,累加到i之后第一次变-, 那么解一定不再[start, i],因此解可以暂时设定为i+1 (为何呢? 因为第一次变-的话,那么前面每次都累加完都是正,如果解再[start+1,i]的话,例如start+1, 那么从start+1开始累加到i一定是负的,因为会比之前的更小,因为start开始第一次累加一定为正,不然就提前结束了)

因此我们维护几个变量
sum: 表示当前累加的和,如果变-了就清了,修改候选的起始点。
total: 计算总的差值,判断题目是否有解
j: 表示当前候选的答案,起始点

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int n=gas.size();
        int total=0, sum=0, j=0;
        for(int i=0;i<n;i++)
        {
            sum+=gas[i]-cost[i];
            total+=gas[i]-cost[i];
            if(sum<0) sum=0, j=i+1;
        }
        return total < 0 ? -1 : j;
    }
};

Posted by richard爱闹 - 6月 2 2015
如需转载,请注明: 本文来自 Richard

GMM

containDuplicateIII
采用二叉排序树,这是第一个,以为里面需要有一个查找nums[i]-t的第一个位置,然后看第一个元素是否<=nums[i]+t, 如果是的话,说明存在,否则就找不到了。

同时维护二叉排序树只有k个元素,如果超过k个元素一定,里面位于最前面的
元素一定是和当前查询的元素index差值超过k的。所以要维护k个元素的二叉排序树即可。

然后利用lower_bound函数就可以实现二叉查找了。

class Solution {
public:
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
        int n=nums.size();
        deque<int> L;
        multiset<int> mul;
        for(int i=0;i<n;i++)
        {
            if(L.size()>k)
            {
                //int cur=;
                mul.erase(mul.find(L.front()));
                L.pop_front();
            }
            auto it=mul.lower_bound(nums[i]-t);
            if(it==mul.end() || (LL)*it>(LL)nums[i]+(LL)t)
            {
                L.push_back(nums[i]);
                mul.insert(nums[i]);
            }
            else return 1;
        }
        return 0;
    }
};

最坑爹的是,这里面用deque可以,但是list来模拟队列就不行。
可能是STL性能的差别。

http://blog.csdn.net/abcjennifer/article/details/8198352

GMM 模型是 一种混合模型,求解用EM算法。

高斯混合模型,多个高斯分布的混合,每个高斯分布有一个混合比例。
p(x)=sum(k=1->k) pi(k)N(x|k),
其中pi是每个分布的权重,N是高斯分布的概率密度函数

这是这个模型的定义。

我们用最大似然估计来求解模型,x1…xN, 每个数据都是从高斯分布中采样,概率p(xi), 因此最大似然估计就是使得这个数据产生的概率最大,假定独立同分布,因此直接乘积,用对数似然可以使得求解方便(Richael Zhang博客里说的是解决下溢的问题)

然后套用EM的框架,具体公式见Richael Zhang的博客,

E步生成r(i, k) 表示xi由第k个正式分布生成的概率
M步估算参数,K个均值向量和协方差矩阵,以及每个分布的混合权重

然后重复迭代直到似然函数收敛

模型:GMM
策略:最大似然估计
算法:EM

Posted by richard爱闹 - 6月 1 2015
如需转载,请注明: 本文来自 Richard

CF301Div2ProB

convex 凸
convave 凹
omit 省略
emit 发射,HMM发射概率

太久没写算法,Partition算法都不会写了 T_T
掌握Partition的要诀就是一点,记忆!

双向扫描版的,最后要把a[low], a[i] swap。我记忆为单向扫描了。

明天就毕业答辩了,感觉硕士三年也走到头了。

是该面对社会了

http://codeforces.com/contest/540/problem/B

这道题目,是构造型算法的贪心。

给定k个数,构造剩余的n-k个数,使得n-k个数都在[1, p],并且数组sum<=x, 并且median>=y

题解是对于剩下数,构造y,使得中位数足够,然后剩下的数都是1,也就是尽可能小,因为sum要<=x, 尽可能小,这种是尽可能小,median不用至少要这么多y才行。

因为y增加的话median一定是增长的,如果前面可以的话,后面一定可以。

int main()
{
/*
#ifndef ONLINE_JUDGE
    freopen ("in.txt" , "r" , stdin);
    freopen ("out.txt" , "w" , stdout);
#endif
*/
    int p ,x, y, n, k;
    while(cin>>n>>k>>p>>x>>y)
    {
        fill_n(a, n, 1);
        int cnt=0;
        for(int i=0;i<k;i++)
        {
            cin>>a[i];
            if(a[i]>=y) cnt++;
        }
        //int i;
        for(int i=k;i<n;i++)
        {
            if(cnt>=(n+1)/2) break;
            a[i]=y;
            cnt++;
        }
        //if(i==n) {puts("-1"); continue;}
        int sum=0;
        for(int i=0;i<n;i++) sum+=a[i];
        if(sum<=x && cnt>=(n+1)/2)
        {
            for(int i=k;i<n;i++) cout<<a[i]<<" ";
            cout<<endl;
        }
        else puts("-1");
    }
    return 0;
}

附上炮哥的一个构造算法,先满足尽可能接近sum,然后再判断中位数是否是y符合的。

int main()
{
/*
#ifndef ONLINE_JUDGE
    freopen ("in.txt" , "r" , stdin);
    freopen ("out.txt" , "w" , stdout);
#endif
*/
    int p ,x, y, n, k;
    while(cin>>n>>k>>p>>x>>y)
    {
        fill_n(a, n, 1);
        for(int i=0;i<k;i++) cin>>a[i];
        int sum=0;
        for(int i=0;i<n;i++) sum+=a[i];
        for(int i=k;i<n;i++)
        {
            if(sum+y-1>x) break;
            a[i]=y;
            sum+=y-1;
        }
        for(int i=0;i<n;i++) b[i]=a[i];
        sort(b, b+n);
        if(sum<=x && b[n/2]>=y)
        {
            for(int i=k;i<n;i++) cout<<a[i]<<" ";
            cout<<endl;
        }
        else puts("-1");
    }
    return 0;
}

炮哥,去了百度记得带我飞啊~~

Posted by richard爱闹 - 5月 30 2015
如需转载,请注明: 本文来自 Richard

Random Alg first blood

3n+1问题,对于任意n,如果奇数,n=3*n+1, 偶数n=n/2,
这个问题3n+1,有结论,任何数都可以规约到1,10000也只要400左右,
但是证明oneness, 是困难的。

python
a=[]
a.sort()才会改变a结构
sorted(a) 只是把a排序结果返回出来,不改变a的结构

http://www.cnblogs.com/kkgreen/archive/2011/08/11/2134647.html

假设你希望以各1/2的概率输出0和1。你可以自由使用一个输出0或1的过程 BIASED-RANDOM。它以概率p输出1,以概率1-p输出0,其中0<p<1,但是你并不知道p的值。给出一个利用BIASED- RANDOM作为子程序的算法,返回一个无偏向的结果。你的算法的期望运行时间是多少?

分析:设计的思路是利用对称性。 假设有两个基于BIASED-RANDOM的伯努利试验序列A、B。每个试验序列都会产生0,1值序列;每一轮A和B各进行一次,如果该轮试验的结果是 ai>bi(即ai=1,bi=0)则算法结束,结果为1;如果ai<bi则算法结束结果为0;如果ai=bi则开始下一轮迭代。

由于每一轮试验都是独立的,所以只要能够证明每一轮在得出结果的条件下,得出1和得出0的概率相等就可以了。

while TRUE 
do 
x = BIASED-RANDOM 
y = BIASED-RANDOM 
if x != y 
then return x 

得出1的概率是p*q  (x得出1,y得出0)

得出0的概率是q*p  (x得出0,y得出1)

精妙!

Admis大神蛋哥推荐的题目

random algorithm

given random 0 or 1, return random integer [a, b]

区间扩增法,每一位编码,由于每个random是独立的,那么就是2^m个数覆盖了b-a+1个数就可以了。

bool Random01()
{
    return rand()%2;
}
int RandInt(int a, int b)//[a, b]
{
    int len=b-a+1;
    int m=ceil(log2(len));
    while(1)
    {
        int num=0;
        for(int i=0;i<m;i++)
        {
            num=num*2+Random01();
        }
        if(num+a<=b ) return num;
    }
}

蓄水池抽样第一发。
给定数组,随机返回数组中最大元素的位置。

假设当前是对n-1的目前最大值返回概率都为1/(n-1), 那么对于第n个元素,

如果说等于当前最大,如果1/n概率选择这个元素,那么前面的元素选中概率是(n-1)/n, 之前每个元素分别为1/(n-1), 那么之前n-1个元素选中概率分别为1/(n-1)* (n-1)/n= 1/n, 第n个元素选中概率是1/n.

如果当前元素更大,那么最大元素只有一个,选中这个概率是1

算法等概率正确性得到证明。

int GetRandomMax(int a[], int n)
{
    int maxx=INT_MIN, pos=-1, num=0;
    for(int i=0;i<n;i++)
    {
        if(a[i]<maxx) continue;
        if(a[i]>maxx) {maxx=a[i], num=1;}
        else num++;
        if(rand()%num==0) pos=i;
    }
    return pos;
}

http://blog.jobbole.com/42550/

Posted by richard爱闹 - 5月 28 2015
如需转载,请注明: 本文来自 Richard