牛客OI賽制測試賽1 題解

數競生:這不是送分的常識嗎
這裏引入一個叫卡西尼恆等式的玩意。
公式表達就是
設$fib[i]$爲斐波那契數列的第$i$項$(i>0,i \in N_+)$
則有
$fib[i+1]fib[i-1]-fib[i]^2=(-1)^i$,其中$(i>1,i \in N_+ )$
由於數聽說明了$i>=2$,因此咱們能夠用數學概括法證實這個結論。
首先看邊界條件,
$fib[1]=fib[2]=1,fib[3]=2$
$fib[3]*fib[1]-fib[2]^2=2*1-1^2=(-1)^2$
因此對於邊界條件成立。
如今,假設此結論對於$i=n$成立。
則有$fib[n+1]fib[n-1]-fib[n]^2=(-1)^n$
又∵$fib[i]=fib[i-1]+fib[i-2]$得出$fib[i+1]=fib[i]+fib[i-1]$
因此有
$fib[n+2]fib[n]-fib[n+1]^2$
$=(fib[n+1]+fib[n])*fib[n]-(fib[n]+fib[n-1])^2$
$=fib[n]^2+fib[n]fib[n+1]-fib[n]^2-fib[n-1]^2-2fib[n]fib[n-1]$
$=fib[n]^2+fib[n](fib[n+1]-fib[n])-fib[n-1]^2-2fib[n]fib[n-1]$
$=fib[n]^2+fib[n]fib[n-1]-2fib[n]fib[n-1]-fib[n-1]^2 $
$=fib[n]^2-fib[n]fib[n-1]-fib[n-1]^2$
$=fib[n]^2-fib[n-1](fib[n]+fib[n-1])$
$=fib[n]^2-fib[n-1]fib[n+1]$
$=(-1)(fib[n]^2-fib[n-1]fib[n+1])$
$=(-1)(-1)^n$
$=(-1)^{n+1}$
因此,此結論對於$i=n+1$也成立$……$
證畢。
因而,$n$爲偶數答案就是$1$不然爲$-1$。高精讀入,判斷一下最後一位就好了。
複雜度$O(1)$
$code:$
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char n[1000010];int l;int num;
int main()
{
    cin>>n;
    int l=strlen(n);
    num=n[l-1]-'0';
    printf("%d",num%2==0?1:-1);
    return 0;
}

 

 
實際上,若是不知道的話,直接打個表就能看出來了。
下面是我比賽的時候打表的$generous$
 
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long long f[100001];
int main()
{
 f[1]=f[2]=1;
 for(int i=2;i<=30;i++)
  f[i+1]=f[i]+f[i-1],
  printf("%lld ",f[i-1]*f[i+1]-f[i]*f[i]);
 return 0;
}

 

此題完結。
恭喜本寶寶傻呵呵的就交上去代碼了$qwq$
而後才發現有錯。
  
#include<cstdio>
#include<iostream> 
using namespace std;
int a,b,c;
 int main(){long long l=1,r=int(1e9)<<1:cin》a>>b;while(r-l>1){c=(l+r)>>1;if(c-b<a)l=c;else if(c-b>a)r=c;else return printf("%d\n",c);
}     if(l!=r)return printf("%d\n",r);
     }

 

不難發現,這裏面又語法錯誤(拿個DEV試一下就知道了應該是兩個,算上$return\ 0$三個)
以後不難發現,是$a+bproblem$我本身手玩了好幾組發現了。
以後拿着$a+b$的正解拍了一萬多組沒出錯。就認爲是對的了。
實際上,寫過$a+b$毒瘤解法的小夥伴們都能一眼看出來。$a+b$交上去就過了。
複雜度$O(1)$
 
C 序列
相信這題數據隨機,因此必定是個暴力。
首先看$q>>n$因此,想到一個記憶化,$ins[i]$表示詢問$i$是否可行$-1,0,1$表示不可行,未知,可行。若是這個詢問以前有過,直接輸出就好,這樣,咱們把$q$降到了$100000$。
以後,有一個顯然的事情就是,當這個序列的全部元素和整除$k$的時候,纔有可能知足。因此,若是$sum%k==0$暴力枚舉便可過。
這裏在說一點,就是,若是$k$可行,則$d$必定可行,其中$d$是$k$的約數。這點顯然,畫個圖就能理解。
因此能夠用莫隊搞一發。按詢問段數$k$從大到小暴力枚舉,若是以前沒被判過且當前可行,則能夠把它的約數都標記爲可行(這個對於小數據可能形成負優化,數據隨機,因此不加這點可過)
而後$……$考場上想了一個奇技淫巧的辦法,只水了$40$
複雜度:$O($玄學,能過$)$
$qwq$
不加優化理論一次$O(n)$,總共$q$次,由於加了記憶化,因此$n,q$同階,最壞$O(nq)$,然而數據隨機 $……$
加優化更玄學$……$須要看數據而定,最壞的話應該能降到均攤根號左右。
 
這題一開始叫CCF的巡查之旅呢 
不難發現,給出的是一棵樹。
因此,咱們直接找出樹的直徑以後再按等差數列求和公式計算便可。
考場上樹的直徑寫成$spfa$沒救了$……$還寫掛了,纔拿了$18$分$qwq$
因此就是樹的直徑的複雜度$O(n)$
這題放到$E$題 真的很$……$不想說啥。
青蛙走過的路線必定是一個子序列
因此直接求一個最長不降低子序列就行。
而後$nlogn$就過了
#include<cstdio>
#include<algorithm>
using namespace std;
int a[400005];
int d[400005];
int main()
{
    int n;
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    if (n==0)
    {
        printf("0\n");
        return 0;
    }
    d[1]=a[1];
    int len=1;
    for (int i=2;i<=n;i++)
    {
        if (a[i]>=d[len]) d[++len]=a[i];
        else
        {
            int j=upper_bound(d+1,d+len+1,a[i])-d;
            d[j]=a[i];
        }
    }
    printf("%d\n",len);   
    return 0;
}

 

 F 子序列
容斥可作。首先算出不考慮去除數的子序列乘積的乘積$……$
每個數都被乘了$C_{n-1}^{k-1}$次,
以後考慮第$i \in 1,n $大的數咱們對它多算的次數,
爲$C_{n-i}^{k-1}+C_{i-1}^{k-1}$次(就是從不選比$i$大的數中共$n-i+1$個數裏選$k$個,和從不比$i$小的$i$數裏選$k$個)
因此容斥一發就行了。
能夠$nlogn$作.
相關文章
相關標籤/搜索