很費勁地 3/10 ,可是校內第18名囧。ios
一開始沒什麼一眼作出來的題;後來發現J題好多人過,因而G開始寫J;但彷佛寫了一會之後遇到了障礙,停下繼續推了起來。而我先看了B,E,F,發現B題漸漸有一些人過了,因而開始看B。此時Y也在看B。一個小時多一點的時候,J過了;Y在看E,我在看B,而後G看F——目前就是B,E,F,J過的人比較多。B應該是 \( O(n^2) \) 作,就開始想DP,可是沒什麼很好的想法。以後Y發現了E題的規律,寫出了個式子,因而我兩人就一塊兒討論怎麼寫出來;討論一番,以爲預處理一下,而後二分就能寫。此時G發現F題能搜索,已寫了半天。而後Y去寫E題,很快寫完,但遇到了點問題,G也去調了半天,就過了。這時已經四點了。G繼續寫F題,而Y和我一塊兒看B題;我又寫了DP的轉移方程,可是怎麼看也是 \( O(n^3) \) 的,苦惱。Y在考慮構造,但也沒想好。還剩十分鐘的時候F題終於過了。因而我上去寫了個B題的簡單假算法,果真WA了,並且還一個點都沒過,真不給面子啊。c++
E:Math算法
題意:數組
\(t\)組數據,每次給一個\(n\),求知足\( (xy+1) | (x^2+y^2) \)的\( (x,y) \)個數,\(1 \leq x,y \leq n\)。\(1 \leq t \leq 10^5, 1 \leq n \leq 10^18\)。ide
分析:spa
經過打表,發現除了\((1,1)\),知足條件的是全部\( (k,k^3) \),以及它們遞推下去的數對;code
就是說,若是\((a,b)\)知足條件,並且是從\((k,k^3)\)推出來的,那麼\( (b,b*k^2-a) \)也是知足條件的數對;ci
因此找到全部知足條件的數對(也不是不少),每次詢問upper_bound便可。get
數字比較大,須要用__int128.博客
Y寫了。
#include<bits/stdc++.h> #define ll long long using namespace std; const int MAXN=1e7+10; ll num[MAXN]; int T,cnt; ll ans; void init(){ num[1]=1;cnt=1; __int128 a,b; for(int i=2;i<=1e6;i++){ a=i;b=i,b=b*i*i; while(b<=1e18){ //if(b==2211||b==2424||b==4863) printf("%lld %lld\n",(ll)a,(ll)b); num[++cnt]=(ll)b; ll t=b; b=b*i*i-a;a=t; //printf("i=%d a=%lld b=%lld\n",i,(ll)a,(ll)b); //if(b>1e18||b<0) printf("i=%d b=%lld\n",i,(ll)b),exit(0); } } sort(num+1,num+1+cnt); cnt=unique(num+1,num+1+cnt)-num-1; } int main() { //freopen("E.in","w",stdout); init(); //printf("cnt=%d\n",cnt); //for(int i=1;i<=40;i++) printf("%d %lld\n",i,(ll)num[i]); for(scanf("%d",&T);T;T--){ ll n; scanf("%lld",&n); ans=upper_bound(num+1,num+1+cnt,n)-num-1; printf("%lld\n",ans); } }
G:Yu Ling(Ling YueZheng) and Colorful Tree
題意:
給定一棵\( n \)個點的樹(有邊權),給\( q \)次操做,分爲兩種:
\( 0 , u , x \) :把點\( u \)染成顏色\( x \),這裏顏色彼此不一樣並且範圍在\( n \)之內;
\( 1 , u , l , r , x \) :查詢離\( u \)最近的、染過色並且顏色\( c \)知足\( l \leq c \leq r , c mod x = 0 \)的祖先到\( u \)的距離。
\( 1 \leq n , q \leq 1.1*10^5 \) 。
分析:
看了第一個經過的隊伍的代碼,居然是樹狀數組套線段樹,複雜度\( O(nlog^2(n)) \),很巧妙。
首先,須要處理\( c \% x = 0 \)這個要求——能夠離線作,而後把操做分類,將有倍數關係的操做創建關係;暫時能夠這樣想。
查詢要找的是祖先——能夠反過來想,染色操做會對被染色點的子樹有影響,而操做子樹貌似比操做祖先方便一些。
綜合起來,咱們能夠先找到每一個顏色的因數,把它們存在vector裏;染上某個顏色的操做會影響到該顏色全部的因數,因而把這個操做分別放進它全部因數的存儲操做的另外一個vector裏;固然,查詢某個顏色的操做也放進那個顏色的操做vector裏;這個vector裏的操做要按順序放。
因而咱們能夠考慮每一個顏色的操做序列;按順序進行修改和查詢操做。
爲了方便地對子樹總體修改,咱們求出這棵樹的dfs序,在dfs序列上用樹狀數組進行區間操做,給染色點的子樹進行某些修改。
下面咱們考慮\( l \leq c \leq r \)這個要求——若是用線段樹維護顏色值序列,那麼這個也能夠方便地查詢;
也就是說,當出現一個查詢操做時,咱們要在查詢點的線段樹內查找\( l , r \)範圍內是否有數——只要有數便可,由於前面只進行過當前顏色的倍數顏色的染色操做。
如今咱們就能夠寫出樹狀數組套線段樹了:樹狀數組建在dfs序列上,其中每一個點有一個線段樹建在顏色數值上;修改操做就是給修改點的子樹中每一個點的線段樹上染色顏色位置\( +1 \),查詢操做就是在查詢點的線段樹上提取\( l , r \)區間的和;
這時查詢操做作了一半——咱們能夠知道對於當前點,有多少個祖先符合條件;
倍增記錄的祖先節點,咱們能夠找一下到哪一個祖先節點時,它也有一樣個數的祖先符合條件;最淺的那個點就是答案,\( dis[u] \)相減即得距離。
那麼空間複雜度怎麼辦?實際上,咱們能夠用到線段樹節點時再把它開出來;而對於每一個顏色的操做咱們最多用到\( qlog^2(n) \)個線段樹點,因此用時再開,用完刪除便可。
時間複雜度是\( O(nlog^2(n)) \)。
(過程當中順便仔細又看了看樹狀數組,這篇博客挺好的。)
代碼以下:
#include<iostream> #include<vector> #define mid ((l+r)>>1) #define pb push_back #define ll long long using namespace std; int const N=110005,M=20000005;/// int n,q,hd[N],nxt[N<<1],cnt,to[N<<1],fa[N][20],dfn[N],ed[N],dcnt; int rt[N],ls[M],rs[M],tcnt,tr[M]; ll w[N<<1],dis[N],ans[N]; vector<int>ele[N]; struct Nd{ int u,l,r,id; }; vector<Nd>v[N]; void init() { for(int x=1;x<=n;x++) for(int j=x;j<=n;j+=x)ele[j].pb(x);//j mod x = 0 同餘類 } void add(int x,int y,ll s){nxt[++cnt]=hd[x]; hd[x]=cnt; to[cnt]=y; w[cnt]=s;} void dfs(int u) { dfn[u]=++dcnt; for(int i=hd[u],v;i;i=nxt[i]) { if((v=to[i])==fa[u][0])continue; fa[v][0]=u; dis[v]=dis[u]+w[i]; //dfs(v);// for(int i=1;i<20;i++) fa[v][i]=fa[fa[v][i-1]][i-1]; dfs(v);//注意順序TAT } ed[u]=dcnt; } //線段樹,序列是染色數值 void chg2(int &x,int l,int r,int p,int s) { if(!x)x=++tcnt; tr[x]+=s; if(l==r)return; if(p<=mid)chg2(ls[x],l,mid,p,s); else chg2(rs[x],mid+1,r,p,s); } int qry2(int x,int l,int r,int ql,int qr) { if(!x||(l>=ql&&r<=qr))return tr[x]; int ret=0; if(mid>=ql)ret+=qry2(ls[x],l,mid,ql,qr); if(mid<qr)ret+=qry2(rs[x],mid+1,r,ql,qr); return ret; } //樹狀數組,序列是dfs序 void chg1(int x,int p,int s){for(;x<=n;x+=(x&(-x)))chg2(rt[x],1,n,p,s);} int qry1(int x,int l,int r){int ret=0; for(;x;x-=(x&-x))ret+=qry2(rt[x],1,n,l,r); return ret;} void dell(int x){for(;x<=n;x+=(x&-x))rt[x]=0;} void del(int x) { while(tcnt)ls[tcnt]=0,rs[tcnt]=0,tr[tcnt]=0,tcnt--; //for(int i=1;i<=n;i++)rt[i]=0; for(Nd it:v[x]) if(it.id==0)dell(dfn[it.u]),dell(ed[it.u]+1); } void work(int x)//樹狀數組單點修改(差分),區間查詢(前綴和) //此處x是顏色 { //printf("x=%d\n",x); for(Nd it:v[x]) { if(it.id==0)//若是是修改,則子樹內各點的線段樹上所染顏色位置+1 { //printf("stchg\n"); chg1(dfn[it.u],it.l,1); chg1(ed[it.u]+1,it.l,-1); //printf("aftchg\n"); } else//若是是查詢 { //printf("stq\n"); int u=it.u,L=it.l,R=it.r,id=it.id; //printf("u=%d L=%d R=%d id=%d\n",u,L,R,id); int num=qry1(dfn[u],L,R),p=u; if(!num){ans[id]=-1; continue;} for(int i=19;i>=0;i--) if(qry1(dfn[fa[p][i]],L,R)==num)p=fa[p][i]; //printf("u=%d p=%d %lld %lld\n",u,p,dis[u],dis[p]); ans[id]=dis[u]-dis[p]; //printf("aftq\n"); } } del(x);//刪除線段樹 } int main() { scanf("%d%d",&n,&q); init(); for(int i=1,u,v,s;i<n;i++) scanf("%d%d%d",&u,&v,&s),add(u,v,s),add(v,u,s); dfs(1); //v[x]:x的0同餘類下的修改與查詢操做,並且是按順序放的 for(int i=1,tp,u,a,b,c;i<=q;i++) { scanf("%d%d%d",&tp,&u,&a); if(tp==0) { for(int it:ele[a])v[it].pb((Nd){u,a,0,0});//it做爲詢問中的x時可查的點增長了 ans[i]=-2; } else { scanf("%d%d",&b,&c); if(((b+1)/c)==((a-1)/c))ans[i]=-1;//(r+1)/x==(l-1)/x,即不存在l--r中的數mod x = 0 else v[c].pb((Nd){u,a,b,i}); } } for(int x=1;x<=n;x++)work(x);//此處x是顏色 for(int i=1;i<=q;i++) if(ans[i]!=-2) if(ans[i]==-1)printf("Impossible!\n"); else printf("%lld\n",ans[i]); return 0; }
題意:
給出\(n\)個點的徹底圖,每條邊是黑色或白色;求同色三角形的個數。\(1 \leq n \leq 8000\)。
分析:
從\(1\)到\(n\),記錄每一個點左邊、右邊的白邊點和黑邊點各有多少個,算出不一樣色三角形的個數;每一個三角形被算了兩邊(三個點中有兩個點連了異色邊),最後除以二,再從全部三角形中減去便可。
G寫了。
#include<bits/stdc++.h> #define ll long long using namespace std; namespace GenHelper { unsigned z1,z2,z3,z4,b,u; unsigned get() { b=((z1<<6)^z1)>>13; z1=((z1&4294967294U)<<18)^b; b=((z2<<2)^z2)>>27; z2=((z2&4294967288U)<<2)^b; b=((z3<<13)^z3)>>21; z3=((z3&4294967280U)<<7)^b; b=((z4<<3)^z4)>>12; z4=((z4&4294967168U)<<13)^b; return (z1^z2^z3^z4); } bool read() { while (!u) u = get(); bool res = u & 1; u >>= 1; return res; } void srand(int x) { z1=x; z2=(~x)^0x233333333U; z3=x^0x1234598766U; z4=(~x)+51; u = 0; } } using namespace GenHelper; int n; ll Tot,Ill; bool Edge[8005][8005]; int Input() { int n, seed; cin >> n >> seed; srand(seed); for (int i = 0; i < n; i++) for (int j = i + 1; j < n; j++) Edge[j][i] = Edge[i][j] = read(); return n; } int main() { n=Input(),Tot=1ll*n*(n-1)*(n-2)/6; for(int i=0;i<n;i++) { ll Rb=0,Rw=0,Lb=0,Lw=0; for(int j=i-1;j>=0;j--) Edge[i][j]?Lb++:Lw++; for(int j=i+1;j<n;j++) Edge[i][j]?Rb++:Rw++; Ill+=Lb*Rw+Lw*Rb+Lw*Lb+Rw*Rb; } printf("%lld\n",Tot-Ill/2); }
https://ac.nowcoder.com/acm/contest/11254/E