【百度之星2014~初賽(第二輪)解題報告】JZP Set

聲明

   筆者最近意外的發現 筆者的我的網站 http://tiankonguse.com/ 的不少文章被其它網站轉載,可是轉載時未聲明文章來源或參考自 http://tiankonguse.com/ 網站,所以,筆者添加此條聲明。php

    鄭重聲明:這篇記錄《【百度之星2014~初賽(第二輪)解題報告】JZP Set》轉載自 http://tiankonguse.com/ 的這條記錄:http://tiankonguse.com/record/record.php?id=668html

 

前言

最近要畢業了,有半年沒作比賽了.
此次參加百度之星第二輪娛樂一下.
如今寫一下 JZP Set 這道題的的解題報告.ios

正文

 

題意

 

題意是:給你n個數(1到n),給你一個規則,問用這個規則能夠獲得多少個合法的集合.函數

具體規則是:一個合法集合裏任意挑兩個數,若是這兩個數之和是偶數,這個偶數除以2獲得的數也要在這個合法集合裏.網站

好比: 3 和9 在集合裏,3+9是偶數,因此 (3+9)/2 = 6 也要在這個集合裏.而後 {3,6,9}就是一個合法的集合.spa

 

起初我理解錯題意了,覺得是任意的兩個數字之和除以2.好比 (3 + 6)/2 = 4, 我覺得4也要在集合裏.htm

因而很快獲得一個 (n+1)*n/2 的公式.blog

後來學弟告訴我正確的題意.遞歸

 

分析

 

這個題的樣例有10^5個,每一個樣例最大是10^7.ci

 

 

錯誤題意

 

首先來看看我理解錯誤題意時,是怎麼作的.

假設 F(n) 是 n 的答案的話, 則 F(n + 1) = F(n) + f(n+1).

f(n+1)裏面確定有 n+1, 我假設f(n+1) 這些集合的任一個集合 S 裏的最小值是 a, 則 (a+n+1)/2 確定在 S 裏面,而後這樣遞歸下去發現 a到n+1的全部數字都必須在 S 裏面.

因而 f(n+1) 就是  n+ 1 了.

因而最終方程就是  F(n+1) = F(n) + n+ 1.

 

只惋惜這是錯誤的題意的作法.

 

正確題意

 

學弟告訴我正確的題意,仍是能夠很快寫出方程來

 

F(n+1) = F(n) + f(n + 1).

 

其中f(n+1) 是含有 n+ 1的合法的集合.

 

奇數偶數合法<

 

首先對於我上面找到的那些確定是合法集合的一部分,只是我遺漏了一些合法集合.

遺漏的確定是非連續的了.

而後很快能夠想到 一個奇數和一個偶數構成的集合都是合法集合.

因而 f(n + 1) 就又加上含有一奇一偶的合法集合的數量了,只是提交後WA了.

 

等差爲奇數的組合

 

而後學弟隨手寫了一個集合 {3, 6, 9 } 發現也是合法集合.

而後我無心見把12添加進去後發現仍是合法集合.

因而咱們得出結論:等差爲奇數的數列都是合法集合,對於連續的那個只不過是等差爲1罷了.

因而咱們假設 i/x 的個數爲 num(i/x),

因而有

 

則最終答案是 

 

C( num (n / 1) , 2) + C( num (n / 3) , 2) + C( num (n / 5) , 2) + ...

也就是等差位 x 的數列裏,咱們隨便挑一段都是合法集合.

只是到這一步咱們發現這樣作仍是超時.

 

遞推的等差數列

 

因爲F(n+1) 與 F(n) 有很大的關係,因此咱們嘗試找找遞推行不行.

仍是這個公式

 

F(n) = F(n-1) + f(n).

f(n) 表明含有 n 的合法集合.

 

而後這些集合須要全是等差數列.

因而寫了這麼一個公式

f(n-1) =

n/1 + n/3 + n/5 + ....

 

 

而後就沒什麼想法了.

 

今天看了這個解題報告才知道能夠這樣作.

發現咱們若是寫出 f(n-2) 那一項的公式

 

(n-1)/1 + (n-1)/3 + (n-1)/5 + ...

這兩個公式大部分項是相等的,只有個別的幾個不相等.

 

本身舉了幾個例子發現 n 整除 下面的項時,這個除式會多一個.

 

好比 n = 12
則 12/3 = 4, 11/3 = 3.

這樣這個f(n)函數就能夠轉化爲

 

 

f( n ) = f( n - 1) + Count( n -1 ).

其中 Count( n  ) 表明 n 的奇數約數個數.

 

而後小舟學長的模板上恰好有求關於小於 n 的全部數的約數的個數.其中有 O( n*log(n) ) 的模板,也有 O( n ) 的模板,

因爲 n*log(n) 的模板比較簡單,也能夠過這道題,因而我就是用 n*log(n) 的模板了.

 

代碼

 

/*************************************************************************
  > File Name: 4.2.cpp
  > Author: tiankonguse
  > Mail: i@tiankonguse.com
  > Created Time: Mon 26 May 2014 01:06:18 PM CST
***********************************************************************/
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<string>
#include<queue>
#include<map>
#include<cmath>
#include<stack>
#include<algorithm>
#include<functional>
#include<stdarg.h>
using namespace std;
#ifdef __int64
typedef __int64 LL;
#else
typedef long long LL;
#endif
const int N = 10000010;
LL nod[N];
LL count[N];
LL ans[N];

void __sieve_nod() {
	memset(nod, 0,sizeof(nod));
    for (int i = 1; i < N; i+=2) {
        for (int j = i; j < N; j += i) {
            ++nod[j];
        }
    }
}

void init(){
	ans[0] = 1;
	ans[1] = 2;
	LL count = 1;
	for(int i=2;i<N;i++){
		count += nod[i-1];
		ans[i] = ans[i-1] + count;
	}
}


int main() {
	__sieve_nod();
	init();
    int t,n;
    scanf("%d",&t);
    for(int i=1; i<=t; i++) {
        scanf("%d",&n);
        printf("Case #%d:\n%I64d\n",i,ans[n]);
    }
    return 0;
}

 

 

參考

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

http://www.cnblogs.com/oyking/p/3751608.html

相關文章
相關標籤/搜索