20181026(整除分塊+概率遞推+樹上操作+(神祕中位數+rmq))

快速荷葉葉變換
(fht.cpp/c/pas)
【問題描述】
荷葉葉是一位偉大的數♂學家。
荷葉葉發明了一個函數,並稱之爲快速荷葉葉變換(Fast H10Transfrom)
FHT(N, M) =在這裏插入圖片描述
但荷葉葉比較懶,對於函數的計算,荷葉葉把這個任務交給了你。
由於答案可能會很大,請輸出答案對1000000007取模的值。
【輸入格式】
一行,包含兩個整數N,M。
【輸出格式】
1個整數,FHT(N,M) mod 1000000007的值。
【輸入輸出樣例】
in
3 4
out
1
【數據規模與約定】
對於 40%的數據,1 ≤N,M≤1000
對於 60%的數據,1 ≤N,M≤106
對於 100%的數據,1 ≤N,M≤109
全國信息學奧林匹克聯賽(NOIP2016)複賽 提高組 day0
第3頁共4頁
幻象
(phantom.cpp/c/pas)
【問題描述】
phantom是一位愛思考的哲♂學家。
最近phantom得到了森の妖精的真傳。在他練功的時候,每秒他的思緒中都有一定的概率浮現出奇♂異的幻象,持續x秒的幻象將產生的幻象值。
phantom練功發自真心,他想知道,在N秒內他期望產生的幻象值是多少。
【輸入格式】
第一行包含1 個正整數 N,表示總時間 N秒。
第二行包含 N個用空格隔開的在[0,100]之間的正整數,其中第i個數a[i]表示第i秒浮現幻象的概率爲百分之a[i]。
【輸出格式】
1個實數,四捨五入後保留一位小數,表示期望幻象值。
【輸入輸出樣例】
in
3
50 50 50
out
2.8
【數據規模與約定】
對於 40%的數據 N ≤ 10
對於 60%的數據 N ≤ 100
對於 100%的數據,N ≤ 106
數據規模較大,請使用效率較高的讀入方式。
全國信息學奧林匹克聯賽(NOIP2016)複賽 提高組 day0
第4頁共4頁
樹上摩托
(sherco.cpp/c/pas)
【問題描述】
Sherco是一位經驗豐富的魔♂法師。
Sherco在第零次聖盃戰爭中取得了勝利,並取得了王之寶藏——王の樹。
他想把這棵樹砍去任意條邊,拆成若干棵新樹,並裝飾在他的摩托上,讓他的摩托更加酷炫。
但Sherco認爲,這樣生成的樹不具有美感,於是Sherco想讓每棵新樹的節點數相同。
他想知道有多少種方法分割這棵樹。
【輸入格式】
第一行一個正整數N,表示這棵樹的結點總數。
接下來N-1行,每行兩個數字X,Y表示編號爲X的結點與編號爲Y的結點相連。結點編號的範圍爲[1,N]。
【輸出格式】
一個整數,表示方案數。注意,不砍去任何一條邊也算作一種方案。
【輸入輸出樣例】
in
6
1 2
2 3
2 4
4 5
5 6
out
3
【數據規模與約定】
對於40%的數據,N ≤ 15
對於60%的數據,N ≤ 105
對於100%的數據,N ≤ 106
數據規模非常大,請使用高效的讀入方式。
2 beautiful
2.1 題目􁧿述
一個長度爲n 的序列,對於每個位置i 的數ai 都有一個優美值,其定義是:找到序列中最
長的一段[l, r],滿足l i r,且[l, r] 中位數爲ai(我們比較序列中兩個位置的數的大小時,
以數值爲第一關鍵字,下標爲第二關鍵字比較。這樣的話[l, r] 的長度只有可能是奇數),r - l

  • 1 就是i 的優美值。
    接下來有Q 個詢問,每個詢問[l, r] 表示查詢區間[l, r] 內優美值的最大值。
    2.2 輸入􁹬􁔿
    第一行輸入n 接下來n 個整數,代表ai 接下來Q,代表有Q 個區間接下來Q 行,每行
    兩個整數l, r(l r),表示區間的左右端點
    2.3 輸出􁹬􁔿
    對於每個區間的詢問,輸出答案
    2.4 Sample Input
    8
    16 19 7 8 9 11 20 16
    8
    3 8
    1 4
    2 3
    1 1
    5 5
    1 2
    2 8
    7 8
    2.5 Sample Output
    7
    3
    1
    3
    5
    3
    7
    3
    3

T1
題意已經給了
整除分塊
移步我的博客
如果你已經會了,那麼實在是,太簡單了。。。

#include<bits/stdc++.h>
using namespace std;
const int mod=1000000007;
long long n,m;
long long ans1,ans2;
int main()
{
	scanf("%d%d",&n,&m);
	ans1=n*n;
	for (long long r,l=1; l<=n; l=r+1)
	  {
	  	if (n/l!=0) r=min(n,n/(n/l)); else r=n;
	  	ans1=(ans1-(l+r)*(r-l+1)*(n/l)/2)%mod;
	  }
	ans2=m*m;
	for (long long r,l=1; l<=m; l=r+1)
	  {
	  	if (m/l!=0) r=min(m,m/(m/l)); else r=m;
	  	ans2=(ans2-(l+r)*(r-l+1)*(m/l)/2)%mod;
	  }
	printf("%lld",(ans1*ans2)%mod);
}

T2
題意概括:每個時刻有a[i]a[i]的概率練功(?),功力收益是連續時長的平方x2x^2(?),求n時刻的功力收益期望

L[i]L[i]爲第ii秒幻象的持續時間的期望.
顯然L[i]=(L[i1]+1)a[i]L[i] = (L[i-1] + 1) * a[i]%
f[i]f[i]表示前ii秒的答案
f[i]=f[i1]+((L[i1]+1)2L[i1]2)a[i]f[i] = f[i-1] + ((L[i-1] + 1)^2 – L[i-1]^2) * a[i]%
時間複雜度爲O(N)O(N)

#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;

double f[1000005],nx[1000005],p[1000005];
int n;

int read(){
    int x=0;
    char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)){
        x=(x<<3)+(x<<1)+(c^'0');
        c=getchar();
    }
    return x;
}

int main(){
    n=read();
    int x;
    for(int i=1;i<=n;i++){
        x=read();
        p[i]=x*1.0/100;
    }
    nx[1]=p[1];
    f[1]=p[1];
    for(int i=2;i<=n;i++){
        nx[i]=(nx[i-1]+1)*p[i];
        f[i]=(f[i-1]-nx[i-1]*nx[i-1]+(nx[i-1]+1)*(nx[i-1]+1))*p[i]+(1-p[i])*f[i-1];
    }
    printf("%.1f\n",f[n]);
}

T3
題意概括:把一棵樹平均分成相同點數相同的塊,求要消去幾條邊。

據我所知,聯通的話,一個節點要聯通,只能往上或者往下,如果說一個節點的size滿足當前要分成的點數,那麼肯定分出來,然後以這個節點爲根的子樹,就能一起往上聯通,作爲這個節點的父親的子樹,如果到了根節點剛好分完,那麼就剛好。

深搜因爲常數太大會爆,O(nn)O(n\sqrt{n})

#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
int head[maxn],n,m,cnt,yin[maxn],cnty,son[maxn],son1[maxn],ce;
bool p;
struct node
{
    int v,nxt;
}e[maxn<<1];
inline void add(int u,int v)
{
    cnt++;
    e[cnt].nxt=head[u];
    e[cnt].v=v;
    head[u]=cnt;
}
inline void build(int u,int fa)
{
 for (int i=head[u];i;i=e[i].nxt)
   {
      int v=e[i].v;
      if (v==fa) continue;
      build(v,u);
      son1[u]+=son1[v];
   }
  son1[u]++;
}
inline int dfs(int u,int fa,int o)
{
    if(son1[u]==o) return o;
    int num=0;
    for (int i=head[u]; i; i=e[i].nxt)
      {
        int v=e[i].v;
        if (v==fa) continue;
        num+=dfs(v,u,o);
        if(son1[u]-num==o) return son1[u];
      }
    return num;
}
int main()
{
    scanf("%d",&n);
    for(int i=1; i<n; i++)
      {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
      }
    for (int i=2; i<=sqrt(n); i++)
      if (n%i==0) {if (i*i==n) {cnty++; yin[cnty]=i;} else {cnty++; yin[cnty]=i; cnty++; yin[cnty]=n/i;}}
    build(1,0);
    int ans=0;
    for (int i=1; i<=cnty; i++)
      if (dfs(1,0,yin[i])==n) ans++;
    if (ans==0) ans=-1;
    printf("%d",ans+2);
}

由此,精簡,如果子樹可以分成每個塊,那麼所有節點能夠剛好除以因數ii的數量等於n/in/i,那麼就可以了

# include <bits/stdc++.h>
using namespace std;
const int root=1;
const int MAXN=1e6+10;
int n,head[MAXN],size[MAXN],tot=0;
struct rec{int to,pre;}a[MAXN*2]; 
inline int read()
{
    int X=0,w=0; char c=0;
    while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
    while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
    return w?-X:X;
}
void adde(int u,int v)
{
    a[++tot].pre=head[u];
    a[tot].to=v;
    head[u]=tot;
}
void dfs1(int u,int fa)
{
    size[u]=1;
    for (int i=head[u];i;i=a[i].pre){
        int v=a[i].to; if (v==fa) continue;
        dfs1(v,u);
        size[u]+=size[v];
    }
}
bool check(int R)
{
    int cnt=0;
    for (int i=1;i<=n;i++)
     if (size[i]%R==0) cnt++;
    return n/R==cnt; 
}
int main()
{
    n=read();
    int u,v;
    for (int i=1;i<n;i++) {
        u=read();v=read();
        adde(u,v);adde(v,u);
    } 
    dfs1(root,-1);
    int ans=0;
    for (int i=1;i<=sqrt(n);i++) {
        if (n%i) continue;
        if (check(i)) ans++;
        if (i!=n/i&&check(n/i)) ans++;
    }
    printf("%d\n",ans);
    return 0;
}

T4
題意概括:?

暴力求中位數然後rmqrmq最大值
rmqrmq詳見我的STST

#include<bits/stdc++.h>
using namespace std;
int n,q;
int a[100100],num[100100],r[1000100];
int f[25][1000100];
int main()
{
//  freopen("beautiful.in","r",stdin);
//  freopen("beautiful.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
    {
        memset(num,0,sizeof(num));
        memset(r,0x7f,sizeof(r));
        r[500000]=i;f[0][i]=1;
        int j=i;
        while(j>1)
        {
            j--;
            if(a[j]>a[i]) num[j]=num[j+1]-1;
            else num[j]=num[j+1]+1;
            r[num[j]+500000]=j;
            if(num[j]==0) f[0][i]=max(f[0][i],i-j+1);
        }
        j=i;
        while(j<n)
        {
            j++;
            if(a[j]>=a[i]) num[j]=num[j-1]+1;
            else num[j]=num[j-1]-1;
            f[0][i]=max(f[0][i],j-r[num[j]+500000]+1);
        }
    }
    for(int i=1;i<=20;i++)
        for(int j=1;j<=n;j++)
            f[i][j]=max(f[i-1][j],f[i-1][j+(1<<(i-1))]);
    scanf("%d",&q);
    while(q--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        int k=log(r-l+1)/log(2);
        int ans=max(f[k][l],f[k][r-(1<<k)+1]);
        printf("%d\n",ans);
    }
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章