1. 程式人生 > >北京DAY1下午

北京DAY1下午

spa 區間查詢 一點 padding print lsp 連接點 date 價值

省選模擬題

周子凱

題目概況

中文題目名

簡易比特幣

計算

路徑

英文題目名

bit

calculation

Path

輸入文件名

bit.in

calculation.in

path.in

輸出文件名

bit.out

calculation.out

path.out

每個測試點時限

1s

2s

1s

內存限制

128M

128M

128M

測試點數目

10

10

10

每個測試點分值

10

10

10

結果比較方式

全文比較(過濾行末空格及文末回車)

題目類型

傳統

1. 簡易比特幣

題目描述

相信大家都聽說過比特幣。它是一種虛擬貨幣,但與普通虛擬貨幣不同的是,它不由某個機構統一發行,而需要利用計算機找出具有特定性質的數據來“發現”貨幣,俗稱“挖礦”。然而,由於具有這種特定性質的數據分布稀疏而無規律,因此挖礦的過程需要投入大量的計算資源來搜尋這些數據。

仿照比特幣是設計思想,我們可以設計一種簡易的比特幣:給定一個由n個非負整數構成的序列{ai},和一個閾值K,如果某個非空子序列(一個連續的區間)中的所有數的異或和小於K,則這個子序列就對應了一個比特幣,否則它毫無價值。

現在,給出這個序列和閾值,請你計算從中能獲得多少個比特幣。

嚴謹起見,簡要解釋一下什麽是異或:

異或是一種位運算,Pascal中寫作xor,C/C++中寫作^。將兩個數寫成二進制形式,然後對每位作“相同得0、不同得1”的運算。例如,12 xor 6 = 10的運算方法如下:

12 = (1100)2

6 = (0110)2

ans= (1010)2 = 10

輸入格式

第一行包含兩個整數n和K,意義如題所述;

第二行包含n個非負整數ai,表示序列中的每一個數。

輸出格式

一行包含一個整數,表示能從序列中獲得的比特幣數。

樣例輸入

3 2

1 3 2

樣例輸出

3

樣例解釋

1 = 1

1 xor 3 = 2

1 xor 3 xor 2 = 0

3 = 3

3 xor 2 = 1

2 = 2

一共3個區間的異或和小於2。

數據範圍

對於20%的數據,n≤100;

對於40%的數據,n≤1000;

另有20%的數據,ai≤50;

對於100%的數據,1≤n≤105,0≤K≤109,0≤ai≤109

2.計算

問題描述

我曾經的競賽教練有一句名言:“人緊張起來的時候會變得和白癡一樣的。”他總愛在比賽前重復這句話。其實論算法,他並沒有教給我們多少,但是回想起以前的經歷發現,至少這句話他說的真是太tm對了。用現在的話講就是:不要慫,就是幹。

oi題很多時候都是這樣,乍一看很難,越看越覺得不可做,於是安慰自己說,肯定又是我沒學過的某算法,做不出很正常。但抱有這種心理的,出了考場往往會被身邊的神犇打臉:“這題其實先oo一下再xx一下就好了,我太弱了搞了一小時才搞出來……”

現在就有一道看上去似乎很不好搞的計算題,請你不慫地算一下怎麽搞。

給出一個長為N的正整數序列,有三種操作:

A l r k b:在區間[l,r]上加上一個首項為b、公差為k的等差數列。即,序列al, al+1, al+2, al+3……變成al+b, al+1+b+k, al+2+b+2k, al+3+b+3k……

B l r:求區間[l,r]內所有數的和mod 1000000007的值

C l r:求區間[l,r]內所有數的平方的和mod 1000000007的值

輸入格式

第一行包含兩個數n、q,表示序列長度和操作的數量;

第二行包含n個數{ai},表示原序列;

接下來q行,每行包含一個操作,格式和意義如題面所述。

輸出格式

輸出若幹行,每個B操作和C操作輸出一行,表示詢問的答案。

樣例輸入

3 3

1 1 1

A 1 3 2 2

B 1 2

C 2 3

樣例輸出

8

74

數據規模

測試點1~2:n, q ≤ 1000;

測試點3~4:k=0,沒有C操作;

測試點5~6:k=0;

測試點7~8:沒有C操作;

對於100%的數據,n, q ≤ 100000,0 ≤ ai, k, b ≤ 109,1 ≤ l ≤ r ≤ n

3. 路徑

問題描述

實在不知道怎麽編題面了,就寫得直白一點吧。反正沒幾個人寫得完三題,估計都看不到這裏。

給出一個仙人掌圖,求圖中最長路的長度。

Emmm……還是稍微具體一點吧。

仙人掌圖是指一個有N個點與M條邊的無向圖,點從1到N標號,每條邊有各自的長度,圖中可能存在若幹個簡單環,但是,每個點最多只會屬於1個簡單環路。簡單環是指一個經過至少兩個點、且不經過重復點的環。(這裏仙人掌圖的定義也許和你在別處見過的不太一樣,請仔細審題)

例如,圖1所示的是一個仙人掌圖,但圖2則不是,因為3號點同屬於兩個簡單環。

技術分享圖片

技術分享圖片

給出一個仙人掌圖,你需要求出圖中的最長路的長度。最長路不能經過重復的點。例如,假設圖中所有邊長度都為1的話,圖1中的仙人掌圖的一條最長路為1-2-3-4-5-6,長度為5。

輸入格式

第一行包含1個整數Q,表示數據組數;

每組數據的第一行2個整數N,M,表示仙人掌圖的點數和邊數;

每組數據的接下來M行,每行3個正整數x,y,z,描述一條連接點x與點y,長度為z的邊。

輸出格式

對於每組數據輸出一行,每行包含一個整數,表示最長路徑的長度。

樣例輸入

2

6 7

1 2 1

2 3 1

3 1 1

3 4 1

4 5 1

5 6 1

6 4 1

4 4

1 2 1

2 3 2

3 4 3

4 1 4

樣例輸出

5

9

數據規模

對於10%的數據,Q ≤ 5,n ≤ 10;

另有20%的數據,滿足n=m+1;

另有20%的數據,滿足n=m;

另有20%的數據,滿足每個環上的點數≤ 20;

對於100%的數據,Q ≤ 1000, 所有測試點的n之和 ≤ 100,000,z≤ 1000。

(T3圖片可能被河蟹,沒有就算了hhh)

今天T1就是Trie樹上異或亂搞,T2玄學線段樹標記應用(區間加等差數列,區間查詢元素和和元素平方和)。

T3還沒講,,,(我明明寫的50分暴力分啊,,,怎麽多騙了20分hhh)

先粘一下我的代碼

T1:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
#define maxn 100005
using namespace std;
int n,k,ch[maxn*35][2],siz[maxn*35];
int tot=0,val,now,ci[35],root=0;
ll ans=0;

inline int read(){
    int x=0;char c=getchar();
    for(;!isdigit(c);c=getchar());
    for(;isdigit(c);c=getchar()) x=x*10+c-0;
    return x;
}

inline void ins(){
    int pos=root,r;
    siz[0]++;
    
    for(int i=30;i>=0;i--){
        r=(ci[i]&now)?1:0;
        if(!ch[pos][r]) ch[pos][r]=++tot;
        pos=ch[pos][r],siz[pos]++;
    }
}

inline int query(){
    int pos=root,an=0,r;
    for(int i=30;i>=0;i--) if(k&ci[i]){
        r=(now&ci[i])?1:0;
        if(ch[pos][r]) an+=siz[ch[pos][r]];
        pos=ch[pos][r^1];
        if(!pos) break;
    }else{
        pos=ch[pos][(now&ci[i])?1:0];
        if(!pos) break;
    }
    
    return an;
}

int main(){
    freopen("bit.in","r",stdin);
    freopen("bit.out","w",stdout);
    
    ci[0]=1;
    for(int i=1;i<=30;i++) ci[i]=ci[i-1]<<1;
    n=read(),k=read();
    now=0,ins();
    for(int i=1;i<=n;i++){
        val=read();
        now^=val;
        ans+=(ll)query();
        ins();
    }
    
    cout<<ans<<endl;
    return 0;
}

T2:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
#define maxn 400005
#define ha 1000000007
using namespace std;
ll hd[maxn],tag[maxn];
ll sum[maxn],sum_t[maxn];
ll sum_c[maxn],n,m,a[maxn>>1];
int le,ri,opt;
ll k,b,pos,ans;
char ch;
bool ww;

inline void pushup(int o,int lc,int rc,ll len){
    sum[o]=sum[lc]+sum[rc];
    if(sum[o]>=ha) sum[o]-=ha;
    sum_t[o]=sum_t[lc]+sum_t[rc];
    if(sum_t[o]>=ha) sum_t[o]-=ha;
    sum_c[o]=(sum_c[lc]+sum_c[rc]+sum[rc]*len)%ha;
}

void build(int o,int l,int r){
    if(l==r){
        sum[o]=a[l],sum_t[o]=a[l]*a[l]%ha;
        return;
    }
    
    int mid=(l+r)>>1,lc=o<<1,rc=(o<<1)|1;
    build(lc,l,mid),build(rc,mid+1,r);
    pushup(o,lc,rc,mid+1-l);
}

inline ll ci1(ll x){
    if(!x) return 0;
    return x*(x+1)/2%ha;
}

inline ll ci2(ll x){
    if(!x) return 0;
    ll an=x*(x+1)>>1ll;
    if(!(an%3)) return an/3%ha*(x*2+1)%ha;
    else return (2*x+1)/3*(an%ha)%ha;
}

inline void change(int o,ll len,ll sx,ll gc){
    hd[o]=(hd[o]+sx)%ha,tag[o]=(tag[o]+gc)%ha;
    sum_t[o]=(sum_t[o]+len*sx%ha*sx%ha+gc*gc%ha*ci2(len-1)%ha+2ll*sx%ha*sum[o]%ha)%ha;
    sum_t[o]=(sum_t[o]+2ll*sx%ha*gc%ha*ci1(len-1)%ha+2ll*gc%ha*sum_c[o]%ha)%ha;
    sum[o]=(sum[o]+sx*len%ha+ci1(len-1)*gc)%ha;
    sum_c[o]=(sum_c[o]+ci1(len-1)*sx%ha+gc*ci2(len-1))%ha;
}

inline void pushdown(int o,int l,int r){
    if(hd[o]||tag[o]){
        int mid=(l+r)>>1,lc=o<<1,rc=(o<<1)|1;
        change(lc,mid-l+1,hd[o],tag[o]);
        change(rc,r-mid,(hd[o]+tag[o]*(mid+1-l))%ha,tag[o]);
        hd[o]=tag[o]=0;
    }
}

void update(int o,int l,int r){
    if(l>=le&&r<=ri){
        change(o,r-l+1,(b+(ll)(l-le)*k)%ha,k);
        return;
    }
    
    pushdown(o,l,r);
    int mid=(l+r)>>1,lc=o<<1,rc=(o<<1)|1;
    if(le<=mid) update(lc,l,mid);
    if(ri>mid) update(rc,mid+1,r);
    pushup(o,lc,rc,mid+1-l);
}

ll query1(int o,int l,int r){
    if(l>=le&&r<=ri) return sum[o];
    pushdown(o,l,r);
    ll an=0,mid=(l+r)>>1,lc=o<<1,rc=(o<<1)|1;
    if(le<=mid) an+=query1(lc,l,mid);
    if(ri>mid) an+=query1(rc,mid+1,r);
    if(an>=ha) an-=ha;
    return an; 
}

ll query2(int o,int l,int r){
    if(l>=le&&r<=ri) return sum_t[o];
    pushdown(o,l,r);
    ll an=0,mid=(l+r)>>1,lc=o<<1,rc=(o<<1)|1;
    if(le<=mid) an+=query2(lc,l,mid);
    if(ri>mid) an+=query2(rc,mid+1,r);
    if(an>=ha) an-=ha;
    return an; 
}

int main(){
    freopen("calculation.in","r",stdin);
    freopen("calculation.out","w",stdout);
    
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++) scanf("%lld",a+i);
    build(1,1,n);
    while(m--){
        ch=getchar();
        while(ch>C||ch<A) ch=getchar();
        if(ch==A){
            scanf("%d%d%lld%lld",&le,&ri,&k,&b);
            update(1,1,n);
        }else if(ch==B){
            scanf("%d%d",&le,&ri);
            printf("%lld\n",query1(1,1,n));
        }else{
            scanf("%d%d",&le,&ri);
            printf("%lld\n",query2(1,1,n));            
        }
    }
    return 0;
}

T3:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
#define maxn 100005
using namespace std;
int n,m,T,st[maxn],tp,tot_len;
int tot,cirpot[maxn],mx1,mx2;
int to[maxn*10],val[maxn*10],ne[maxn*10];
int hd[maxn],dis[maxn],num,ans;
bool v[maxn],is_cc[maxn],hhh;

inline void init(){
    num=ans=tp=tot=tot_len=0;
    hhh=0;
    mx1=mx2=0;
    memset(hd,0,sizeof(hd));
    memset(dis,0,sizeof(dis));
    memset(is_cc,0,sizeof(is_cc));
    memset(v,0,sizeof(v));
}

inline void add(int uu,int vv,int ww){
    to[++num]=vv,ne[num]=hd[uu],hd[uu]=num,val[num]=ww;
    to[++num]=uu,ne[num]=hd[vv],hd[vv]=num,val[num]=ww;    
}

void dfs(int x,int len){
    ans=max(ans,len);
    v[x]=1;
    for(int i=hd[x];i;i=ne[i]) if(!v[to[i]]) dfs(to[i],len+val[i]);
    v[x]=0;
}

void tree_dp(int x,int fa){
    for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa&&!is_cc[to[i]]){
        tree_dp(to[i],x);
        ans=max(ans,dis[x]+dis[to[i]]+val[i]);
        dis[x]=max(dis[x],dis[to[i]]+val[i]);
    }
}

void find_circle(int x,int fa){
    st[++tp]=x,v[x]=1;
    for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa&&!hhh){
        if(v[to[i]]){
            hhh=1;
            int h;
            for(h=tp;h;h--) if(st[h]==to[i]) break;
            for(;h<=tp;h++) is_cc[st[h]]=1,cirpot[++tot]=st[h];
            
        }
        else find_circle(to[i],x);
    }
    tp--;
}

int hh(int x){
    if(x==tot+1) return 0;
    for(int i=hd[cirpot[x]];i;i=ne[i]) if(to[i]==cirpot[x%tot+1]) return val[i]+hh(x+1);
    return 123445;
}

void get(int x,int dd){
    tree_dp(cirpot[x],0);
    ans=max(ans,max(dis[cirpot[x]]+mx1+dd,dis[cirpot[x]]+mx2-dd));
    mx1=max(mx1,dis[cirpot[x]]-dd);
    mx2=max(mx2,tot_len+dis[cirpot[x]]+dd);
    if(x==tot) return;
    for(int i=hd[cirpot[x]];i;i=ne[i]) if(to[i]==cirpot[x+1]) get(x+1,dd+val[i]);
}

int main(){
    freopen("path.in","r",stdin);
    freopen("path.out","w",stdout);
    
    scanf("%d",&T);
    for(int l=1;l<=T;l++){
        init();
        scanf("%d%d",&n,&m);
        int uu,vv,ww;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&uu,&vv,&ww);
            add(uu,vv,ww);
        }
        
        if(n>=m){
            if(n==m+1) tree_dp(1,1);
            else{
                find_circle(1,1);
                tot_len=hh(1);
                get(1,0);
            }
        }else{
            for(int i=1;i<=n;i++) dfs(i,0);
        }
        
        printf("%d\n",ans);
    }
    
    return 0;
}

T3竟然是找環之後單調隊列????

代碼難度->INF

(神TM仙人掌,這個坑回來一定要填)

北京DAY1下午