北京DAY1下午
省選模擬題
周子凱
題目概況
中文題目名 |
簡易比特幣 |
計算 |
路徑 |
英文題目名 |
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下午