Expectation MaxNum

VIJOS 情人节比赛
https://vijos.org/p/1919

这题是算数学期望题目,关键是怎么算的快,不能越界,不能丢精度,关于精度问题好像不是特别重要,关键是不越界。

一共m朵花,第i朵有i片花瓣,i=1…m, 一共随机n次,每次选一朵花,问这n次选到的一朵花花瓣数最大值的期望是多少。

典型数学题,先列公式,E=sum(i=1..m) i(i^n-(i-1)^n)/m^n, 直接计算出现指数,m n较大,显然不行,除非高精度,不过太费周折,
于是简化公式,把公式展开,带i的一坨变为 1
1^n-10^n+22^n-21^n+….mm^n-m(m-1)^n=mm^n-(1^n+…(m-1)^n)/m^n, 当时
还一直在想有没有1^n+..m^n的求和公式,结果发现特别复杂,看来不对,不过一看这个,已经可以计算了,因为每一项都可以除以分母了,是小数的指数次
于是直接列公式搞定。

估计有更直接的列公式的方法,可能可以直接到最后一步。

代码如下:

int main()
{
    int m, n;
    while(cin>>m>>n)
    {
        double sum=m;
        for(int i=1;i<m;i++)
        {
            sum-=pow(double(i)/m, n);
        }
        printf("%.4f\n", sum);
    }
    return 0;
}

这里面有一点组合数学的技巧,或者说对立事件,例如选择最大为i的次数,用1…i里面选n次,减去1..i-1里面选n次,这样剩下的就是至少选一次i片花瓣的次数了,

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

Prime Ai Algo

对埃拉托斯特尼筛法进行总结,听名字数学味道就很重。
这个算法,我当时面百姓网的时候遇到了,而且我在C语言助教期中考试答题第一题就是这个,当时小胖帮我改估计只有i*i的才拿满分,
由于改的过于苛刻,差点出了教学事故。

通过筛选i(2….n/2(sqrt(n)))的倍数来去掉合数,这里面主流的分成两个写法,一种是

筛选2*i开始

P[1..n]=0//all primes initially
for(i=2=>n/2, i++)
{
    if(!P[i])
    {
        for(j=2i->n, j+=i) P[j]=1;
    }
}

筛选i*i开始

P[1..n]=0//all primes initially
for(i=2=>sqrt(n), i++)
{
    if(!P[i])
    {
        for(j=i*i->n, j+=i) P[j]=1;
    }
}

筛法时间复杂度当时雅虎群里一哥们说是nlglgn, 并发了一个wiki证明过程,几乎线性吧,上述两种第二种测试比较快,通过分析也是
显然的,举例6在2i方法里会筛两次,3i(2), 2i(3), 而后者只会出现一次,i(2)(i+1), 也即后者保证第二个数比第一个数大,这样不重复筛,
但是渐进时间复杂度并没有大的改善,应该是常数项的改进。

之前fb hackerup round1第一题是一道求[a,b]以内素因子个数为k的数的个数,这道题目其实是算素因子,我却没有想到好的算法,暴力搞,结果超时了,
没跑出来,后来看了G神代码,发现居然是埃式筛法,原来埃式筛法还可以算素因子个数,我果然思考的太少,只知道举一不会反三,只会这题,不会这一系列的题目
,但是必须用2i的埃式筛法,第二种错误,例如6有2 3两个素因子,在2i 版本里,出现两次刚好筛了2 3两个素数的倍数,而ii里面,只会2(2+1)里面出现一次,漏掉3的两倍这样
一个素数因子3。当时在美国最后一天,住在姚立夫家里,姚立夫真是慷慨,让我睡床,他睡沙发。可能由于时差的关系,晚上很晚就困,早上6点多就醒来,FB上闲逛,发现hackerup,还有一点时间结束,于是打算看一题。

所以要学会举一反三,再次膜拜G神,太厉害了。

总结就是,如果算一定范围内的素数,用ii 2i都可以,但是ii更快一些,但只是常数级别上,而算素因子个数只能2i.另外要学会多思考,多举一反三。

题目:https://www.facebook.com/hackercup/problems.php?pid=582396081891255&round=344496159068801
核心代码:

void F(int n)//Print primes in [1..n]
{
    memset(P, 0, sizeof(P));
    //fill(P, P+maxn, 1);
    for(int i=2;i<=n;i++)
    {
        if(!P[i])
        {
            for(int j=2*i;j<=n;j+=i)
                P[j]++;
        }
    }
    //for(int i=2;i<=n;i++) if(!P[i]) cout<<i<<" ";
}

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

Math

昨晚CF的B题,由于昨晚和别人聊天,就没做啦,也是因为昨晚OJ太不给力,第一题始终不给答案,我比较蛋疼。

http://codeforces.com/contest/513/problem/B2

第二题是找mth permutation 使得所有子序列的最小值累加和达到最大,什么意思呢,所有permutation有一个最大和,而且有很多个,从这些里找到
字典序第m个,今天实验室聚餐吃完,我坐在躺椅上想,发现实际就是2^(n-1)个,然后1<=m<=2^(n-1), 因为最大,1不能再中间,不然某一次2元就有两个1 ,
而实际最大sum 一定是sum(i=1->n) (i(i+1)/2), 由此2也不能是边上,但是可以12… 因此我YY了一个算法,就是for 1->n, 每次从当前的边界两个选一个,然后剩下的里面也是
边界选2, 例如这样就有1.。。2 12.。。。 2.。。1 。。。。21 这样四个,其实2^(n-1) 是从算法里算出来的= =, 然后就可以了哇谁,算法复杂度瞬间从n^2*n!降到n了
其实直接上类似求第k个全排列就不需要枚举全部,例如LC上的康拓编码,和那个如出一辙,找规律。

另外我已经第N+1 次饭了 ULL m=1<<(n) 的错误了,当n>=32, 一定要写 ULL m=1ULL<<(n), 因为整数常数默认int, 浮点数默认double, 要么就别装逼,用一个pow, 就不会出错,
然后循环里一直除2

代码如下

int main()
{
    while(cin>>n>>m)
    {
        int ans[n];m--;
        int s=0, e=n-1;
        for(int i=1;i<n;i++)
        {
            ULL mod=(1ULL<<(n-1-i));
            if(m/mod==0) ans[s++]=i;
            else ans[e--]=i;
            m%=mod;
        }
        ans[s]=n;
        for(int i=0;i<n;i++) cout<<ans[i]<<" ";
        cout<<endl;
    }
    return 0;
}

再附上暴力法

bool u[maxn];
int num[maxn];
vector<int> cur, ans;
int sum, n, ki;
ULL m;
int f(vector<int> cur)
{
    int sumf=0;
    for(int i=0;i<n;i++)
    {
        int minx=INT_MAX;
        for(int j=i;j<n;j++)
            minx=min(minx, cur[j]), sumf+=minx;
    }
    return sumf;
}
void dfs(int i)
{
    if(i>=n)
    {
        int fsum=f(cur);
        if(fsum==sum)
        {
            if(ki==m)
                ans=cur;
            ki++;
        }
        return ;
    }
    for(int j=0;j<n;j++)
    {
        if(!u[j])
        {
            u[j]=1;
            cur.push_back(num[j]);
            dfs(i+1);
            cur.pop_back();
            u[j]=0;
        }
    }
}


int main()
{
    while(cin>>n>>m)
    {
        int ans[n];m--;
        int s=0, e=n-1;
        for(int i=1;i<n;i++)
        {
            ULL mod=(1ULL<<(n-1-i));
            if(m/mod==0) ans[s++]=i;
            else ans[e--]=i;
            m%=mod;
        }
        ans[s]=n;
        for(int i=0;i<n;i++) cout<<ans[i]<<" ";
        cout<<endl;
        /*
        sum=0;
        for(int i=1;i<=n;i++) sum+=(i*(i+1)), num[i-1]=i;
        sum/=2;
        ki=1;cur.clear();ans.clear();memset(u, 0, sizeof u);
        dfs(0);
        for(int i=0;i<n;i++) cout<<ans[i]<<" ";
        cout<<endl;*/
    }
    return 0;
}

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

reCAPTCHA

有人说,人活着就是为了装逼,谁叫我是B哥呢,今天偶然看到微博yangqiang分享的standord一哥一年8偏顶会一作,这哥们本科还是学生物的。。和我都是08级
汉。。http://web.stanford.edu/~jiweil/Publications_ByYear.html

然而看到中文写她母亲和他的故事的时候,我被感动,难道是上天为了平衡一个人的得失的安排么,我有点相信神的存在了
http://web.stanford.edu/~jiweil/remembering_my_mom.pdf

今晚看了下自己面FB拍的Stanford的照片,于是闲的蛋疼随便翻了一下斯坦福一些装逼哥的主页,发现一东洋鬼子搞了一个无比装逼的东西,
https://clr3.com/
左侧邮箱验证部分。我投降了,这逼装的实在太厉害了。

大概功能就是想看我的email地址,先弹出一框,输个验证码一样的东西再看。哥看日本鬼子不顺眼,但是这逼装的实在不错,于是打算拷贝一下,
谁叫我是B哥呢。

于是看到了CMU做了一个类似cloud sourcing 的东西,还是夫神告诉我叫这名的,相当于人类为OCR做一些贡献,同时又避免别人爬到我的email,乱发spam email,
实在是一举两得,于是搜到一个逼格有点高的reCAPTCHA,被Google收购了,壮哉大Google,然后我捣腾了一小会儿,从google项目主页获取了一些验证code,
然后自己主页也搞了个这装逼的东西,瞬间B格高起来了: )
http://admis.fudan.edu.cn/~rczhang/

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

Find Missing Number

这题算法不好归为那类,大概是交换类算法吧

class Solution {
public:
    int firstMissingPositive(int A[], int n) {
        for(int i=0;i<n;)
        {
            int cur=A[i]-1;
            if(cur<0 || cur>=n || A[cur]==A[i])//这里几次都犯了错误,写成cur==i, cur==i蕴含了A[cur]==A[i],这里应该
            即使是遇到和要交换的数相同,也不能交换,例如1 1这种会死循环,所以写A[cur]==A[i]
            {
                i++;
                continue;
            }
            swap(A[i],A[cur]);
        }
        for(int i=0;i<n;i++)
        {
            if(A[i]!=i+1)
                return i+1;
        }
        return n+1;//这里第一次写的时候,还漏掉了,因为可能真个数组都是1..n 那么n+1 就是返回值了
    }
};

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

facebook hackerup round 1 Prob 3

最近对于邓紫棋的泡沫上瘾了,今天终于被老板从梦中给醒过来了,浪费了太多时间,那些网有啥用呢,一定要做有用的事情

Facebook hackerup round 1 problem C

Winning at Sports25 points
Download Input File
In the game of Sports, the object is have more points than the other team after a certain amount of time has elapsed. Scores are denoted by two hyphen-separated integers. For example, scores may include 3-2, 4-1, or 10-0. The first number is how many points you’ve scored, and the second is the number of points scored by the opposing team. You’re very good at Sports, and consequently you always win. However, you don’t always achieve victory the same way every time.

The two most extreme kinds of victory are called stress-free and stressful. In a stress-free victory, you score the first point and from then on you always have more points than your opponent. In a stressful victory, you never have more points than your opponent until after their score is equal to their final score.

Given the final score of a game of Sports, how many ways could you arrange the order in which the points are scored such that you secure a stress-free or stressful win?

Input
Input begins with an integer T, the number of games you’ll play. For each game, there is one line containing the final score of the game in the format described above.

Output
For the ith game, print a line containing “Case #i: “ followed by two space-separated integers, the number of ways you can achieve a stress-free or stressful win, respectively. Since these numbers may be very large, output them modulo 1,000,000,007.

Constraints
1 ≤ T ≤ 100
Since you always win, the first number in any final score will always be larger than the second. Both scores will be non-negative integers not exceeding 2000.

Explanation of Sample
In the third test case, you can get a stress-free win by scoring points 1, 2, and 4, or points 1, 2, and 3. You can get a stressful win by scoring points 2, 4, and 5, or points 3, 4, and 5.

Example input · DownloadExample output · Download
5
2-1
3-1
3-2
10-5
1000-500
Case #1: 1 1
Case #2: 2 1
Case #3: 2 2
Case #4: 1001 42
Case #5: 70047606 591137401

这道题目咋一看是一道组合题,但是夫神提示之后,才发现是DP。现在感觉写个新的DP并没有一开始学算法课那么深奥了,只要递归几乎都是可以转DP,
也就是把状态存下来,关键是设计DP的状态和转移方程,这题转移比较直观,设计状态是A和B的得分,那么f(i, j) 只可能和f(i-1, j) 和f(i, j-1) 产生
瓜葛,比其他的DP要简单。

代码如下:

ULL SFree[maxn][maxn], SFul[maxn][maxn];
int Sa, Sb, T;
int ansa, ansb;
char ch;
ULL MD=1000000007;
void Solve()
{
    memset(SFree, 0, sizeof(SFree));
    for(int i=0;i<=Sa;i++)
    {
        for(int j=0;j<=Sb;j++)
        {
            if(i<=j) continue;
            if(i>=1 && j>=1)
                SFree[i][j]=(SFree[i-1][j] +SFree[i][j-1])%MD;
            else if(j==0 && i>0)
                SFree[i][j]=1ULL;
        }
    }

    memset(SFul, 0, sizeof(SFul));
    for(int i=0;i<=Sa;i++)
    {
        for(int j=0;j<=Sb;j++)
        {
            if(i==0) SFul[i][j]=1ULL;
            else if(j==0)
            {
                if(Sb==0) SFul[i][j]=1ULL;
            }
            else
            {
                if(i<=j || j>=Sb)
                    SFul[i][j] =(SFul[i-1][j]+SFul[i][j-1])%MD;
            }
        }
    }
    ansa=SFree[Sa][Sb], ansb=SFul[Sa][Sb];
}

int main()
{
    freopen("winning_at_sports-in.txt", "r",stdin);
    freopen("winning_at_sports-ifout.txt","w",stdout);
    cin>>T;
    for(int Ti=1;Ti<=T;Ti++)
    {
        cin>>Sa>>ch>>Sb;
        Solve();
        cout<<"Case #"<<Ti<<": "<<ansa<<" "<<ansb<<endl;
    }
    return 0;
}

stress-free是一路领先,但是处理b=0的时候是特殊的,这点一开始没有考虑到。现在有一个新的处理边界if else的情况,就是用矩阵划分来弄,
例如if(i==0) 就把第一行去掉,else if (j==0) 就是除掉(0,0) 外的第一列元素,然后再else剩下的i>=1 j>=1的元素这样就不太会出错了,嗯,新技能
get, 计算机很注重离散量和逻辑处理,这方面没有高中数学的训练基础,非常弱,再加上本科有没搞ACM,课程要求太低,学的很不认真,课后题没有做几道。
显得更加单薄,但是对于分析递推公式当成数列题来解我还是比较喜欢的,因为毕竟高中数学的中等难度的数列题是非常喜欢的。

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

install ubuntu on win7 not wubi

安装Linux操作系统,这次想直接裸着装,不玩wubi和虚拟机。

之前磁盘是动态盘,一直以为要全部格掉盘才可以。但是通过搜索发现可以直接转基本盘,而不需要格掉整个盘。这个软件是傲梅分区助手,然后
可以直接转化为基本盘。

首先分了100G做Ubuntu,然后安装时候分四个分区\, \boot, \home 和swap,home比较重要,分大一点,boot是作为安装时device boot install选择的。
这里千万不要选整个磁盘,这里是/dev/sda, 因为这样会覆盖windows的启动项。

但是这样的话,系统找不到linux的grub,所以需要一个叫做EasyCD的软件,收费的,然后add new entry就可以自动检测到linux了,设置grub2

缺点是windows 7 不能识别Linux的文件系统,少了100GB,但是Linux可以识别Windows的文件系统,少了100GB差不多。

EasyBCD配置 以及分区设置
http://blog.sina.com.cn/s/blog_6432901c0100wbjr.html

反面例子,不要选这个device boot, 这样可能会覆盖windows启动项
http://www.zhihu.com/question/20565314

遇到的问题。

  1. wubi只能装在C盘,之前自己用Win7自带磁盘分区来分区,但是发现还是动态盘,Linux不能识别。
  2. 分了一个新的卷后,发现傲梅不能弄了,但是变回去之后,发现可以转了,申请
  3. 于是先转基本盘,然后分了一个新的逻辑分区来Ubuntu
  4. 到了安装时,还需要分最好4个分区,如上,其中一个boot很重要,需要选择这个作为引导项

完成了农行卡的K包登陆,转用户名密码登陆

解决 the-remote-end-hung-up-unexpectedly-while-git-cloning 错误,原因就是文件太大了,加大buffer就可以了: )
http://stackoverflow.com/questions/6842687/the-remote-end-hung-up-unexpectedly-while-git-cloning

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

CF 287 Div 2 C

recursive

这道题目是 递归算法,但是对于左子树的 递归还是没理解,先放在这里

核心函数
ULL solve(int h, ULL n)
{
if(!h) return 0;//n=1
ULL LeftLeafNum=(1ULL<<(h-1));
if(n<=LeftLeafNum) return 1+solve(h-1, LeftLeafNum-n+1);
else return 2*LeftLeafNum+solve(h-1, n-LeftLeafNum);
}

右子树的可以理解,就是左子树,如果一开始要向右走的没理解

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

matlab read file

大家好,这里是记录matlab programming,因为要用fft,所以matlab比较方便些。

读取文件有dlmread, load fgetl textread等多种读文件的API,但是由于我生成的序列数据并非完全一样长,有点偏差,
load dlmread 都是读取matrix数据的,因此只能老老实实用fgetl 一行一行来

dlmwrite 前面是-append, 后面参数列表要每个属性对应一个
dlmwrite(‘FourierFeature.txt’,FourierFeature,’-append’,’delimiter’,’\t’);

Git用法
…or create a new repository on the command line

echo # MCluster_VS2010 >> README.md
git init
git add README.md
git commit -m “first commit”
git remote add origin git@github.com:zhangruichang/MCluster_VS2010.git
git push -u origin master
…or push an existing repository from the command line

git remote add origin git@github.com:zhangruichang/MCluster_VS2010.git
git push -u origin master
…or import code from another repository

You can initialize this repository with code from a Subversion, Mercurial, or TFS project.

Import code

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