刷題#R10

這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述

T1
理解題意,模擬即可。
T2
and是遞減的,or是遞增的。
用倍增預處理。
然後枚舉左端點,二分右端點的範圍或者用倍增求右端點的範圍。
建議用倍增法,因爲二分好像很慢,我的二分T掉三個點,二倍增查找0.1秒。
T3
樹上dp+dfs來優化。
分析:顯然的,樹形dp,狀態也很好想到:f[i][j]表示以i爲根的子樹收集到j個果子的方案數.轉移的話就相當於是揹包問題,每個子節點可以選或不選.如果不選子節點k的話,那麼以k爲根的子樹的邊無論斷不斷都沒關係,貢獻就是f[i][j] * 2^(size[k]).如果選的話,枚舉一下收集到多少個果子,對答案的貢獻就是f[i][j - p] * f[k][p].基本的計數原理.
不過這個轉移是O(n^3)的,怎麼優化呢?狀態定義爲這個樣子是沒法繼續優化的,如果把狀態的表示改成dfs到第i個點,收集到j個果子的方案數,就能夠神奇地做到O(n^2)了.因爲dfs是每次先向下遞歸,然後子節點向上回溯嘛,向下遞歸的時候就用父節點的狀態去更新子節點的狀態,向上回溯就用子節點的答案去更新父節點的答案.也就是說:向下走,更新狀態;向上走,統計答案.

T1

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,p,k,a[1009],b[1009],c[1009][1009];
int main()
{
    freopen("rotate.in","r",stdin);
    freopen("rotate.out","w",stdout);
    scanf("%d%d%d",&n,&p,&k);
    for(int i=1;i<=n;i++) b[i]=i;
    for(int i=1;i<=p;i++)
    {
        scanf("%d",&m);
        for(int j=1;j<=m;j++) scanf("%d",&c[i][j]);
        c[i][0]=m;
    }

    for(int i=p;i>=1;i--)
    {
        m=c[i][0];
        int t=b[c[i][m]];
        for(int j=m;j>1;j--)
        {
            b[c[i][j]]=b[c[i][j-1]];
        }
        b[c[i][1]]=t;
    }
    for(int i=1;i<=n;i++) a[b[i]]=i;
    for(int i=1;i<=n;i++) printf("%d ",a[i]);
    return 0;
}

T2

倍增查找

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
const int MOD=(1e9)+7;
const int N=100009;
int n,a[N];
int f[N][50],g[N][50];
int A,B,C,D;
LL ans;
int main()
{
    freopen("range.in","r",stdin);
    freopen("range.out","w",stdout);
    scanf("%d%d%d%d%d",&n,&A,&B,&C,&D);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),f[i][0]=g[i][0]=a[i];

    for(int j=1;(1<<j)<=n;++j)
    {
        for(int i=1;i<=n;i++)
        {
            if(i+(1<<j)-1>n) break;
            f[i][j]=f[i][j-1] & f[i+(1<<j-1)][j-1];
            g[i][j]=g[i][j-1] | g[i+(1<<j-1)][j-1];
        }
    }//倍增預處理 

    for(int l=1;l<=n;l++)
    {
        if(g[l][0]>D||f[l][0]<A) continue;
        int i,j,L=l,R,andn=(1<<20)-1,orn=0;

        for(i=20;i>=0;i--)
        {
            if(L+(1<<i)-1>n) continue;

            if(((andn&f[L][i])>B)||((orn|g[L][i])<C))
            {
                andn &=f[L][i];
                orn |=g[L][i];
                L+=(1<<i);
            }
        }

        R=L;
        for(i=20;i>=0;i--)
        {
            if(R+(1<<i)-1>n) continue;

            if(((andn&f[R][i])>=A)&&((orn|g[R][i])<=D)) 
            {
                andn &=f[R][i];
                orn |=g[R][i];
                R+=(1<<i);
            }
        }
        R--;
        if(R-L+1>0)
            ans+=(R-L+1);
    }
    ans%=MOD;
    printf("%lld\n",ans);
    return 0;
}

二分(70分)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
const int MOD=(1e9)+7;
const int N=100009;
int n,a[N];
int f[N][50],g[N][50];
int A,B,C,D;
LL ans;
int ask_and(int l,int r)
{
    int t=r-l+1;
    t=log2(t);
    return f[l][t] & f[r-(1<<t)+1][t];
}
int ask_or(int l,int r)
{
    int t=r-l+1;
    t=log2(t);
    return g[l][t] | g[r-(1<<t)+1][t]; 
}
int main()
{
    freopen("range.in","r",stdin);
    freopen("range.out","w",stdout);
    scanf("%d%d%d%d%d",&n,&A,&B,&C,&D);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),f[i][0]=g[i][0]=a[i];

    for(int j=1;(1<<j)<=n;++j)
    {
        for(int i=1;i<=n;i++)
        {
            if(i+(1<<j)-1>n) break;
            f[i][j]=f[i][j-1] & f[i+(1<<j-1)][j-1];
            g[i][j]=g[i][j-1] | g[i+(1<<j-1)][j-1];
        }
    }//倍增預處理 

    for(int i=1;i<=n;i++)
    {
        if(f[i][0]<A||g[i][0]>D) continue;
        int L,R,andn,orn,mid;
        for(int j=i;j<=n;j++)
        {
            andn=ask_and(i,j);
            orn=ask_or(i,j);
            L=j,R=n+1;
            while(L<=R)
            {
                mid=(L+R)>>1;
                if(orn==ask_or(i,mid) && andn==ask_and(i,mid)) L=mid+1;
                else R=mid-1;
            }
            if(orn<=D&&orn>=C&&andn<=B&&andn>=A) ans+=R-j+1;

            j=R;
        }
    }
    ans%=MOD;
    printf("%lld\n",ans);
    return 0;
}

T3
std

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
LL mod = 1e9+7;
int n,k;
int a[1005];
int H[1005],X[2005],P[2005],tot;
inline void add(int x,int y){
    P[++tot]=y;X[tot]=H[x];H[x]=tot;
}
LL pw2[1005];
LL dp[1005][1005];

int dfs(int x,int fa){
    int siz=1;
    for(int i=H[x];i;i=X[i]){
        if(fa == P[i]) continue;
        for(int j=0;j<=n-a[P[i]];j++){
            dp[P[i]][j+a[P[i]]] = dp[x][j];
        }
        int tmp = dfs(P[i],x);
        for(int j=0;j<=n;j++){
            dp[x][j] = (pw2[tmp-1] * dp[x][j] % mod + dp[P[i]][j])% mod;
        }
        siz+=tmp;
    }
    return siz;
}
int main(){
    freopen("fruit.in","r",stdin);
    freopen("fruit.out","w",stdout);
    scanf("%d%d",&n,&k);

    pw2[0]= 1;
    for(int i=1;i<=n;i++) pw2[i] = pw2[i-1] * 2 % mod;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    for(int i=1,x,y;i<n;i++){
        scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }
    dp[1][a[1]] = 1;
    dfs(1,0);

    printf("%d\n",(int)dp[1][k]);

    return 0;
}
發佈了339 篇原創文章 · 獲贊 240 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章