10.27 考試
阿新 • • 發佈:2017-10-28
amp ++ pre d+ clas class first 結構 sizeof
T1
大水題+模擬
直接二分$O(nlogn)$
然而有趣的是我在確認輸入不會炸long long後
認為中間的乘法也不會炸
然後就從考完試到下午4點,一直在調,重打了兩遍...
就差3個1LL...
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int usingT1namespace std; inline void read(int &x) { x=0; int ff=1; char q=getchar(); while(q<‘0‘||q>‘9‘) { if(q==‘-‘) ff=-1; q=getchar(); } while(q>=‘0‘&&q<=‘9‘) x=x*10+q-‘0‘,q=getchar(); x*=ff; } const int N=100006; struct JI { int lx,ly,rx,ry; }ji[N]; bool cmp_x(JI a,JI b) {if(a.lx==b.lx) return a.ly<b.ly; return a.lx<b.lx; } bool cmp_y(JI a,JI b) { if(a.ly==b.ly) return a.lx<b.lx; return a.ly<b.ly; } int n; ll an,an2; int er1(int x,int y,int l) { int r=n,mid,ans=0; while(l<=r) { mid=(l+r)>>1;if(ji[mid].lx>x) r=mid-1; else if(ji[mid].lx<x) l=mid+1; else { if(ji[mid].ly<=y) ans=mid,l=mid+1; else r=mid-1; } } return ans; } int er2(int x,int y,int l) { int r=n,mid,ans=0; while(l<=r) { mid=(l+r)>>1; if(ji[mid].ly<y) l=mid+1; else if(ji[mid].ly>y) r=mid-1; else { if(ji[mid].lx<=x) ans=mid,l=mid+1; else r=mid-1; } } return ans; } void work() { rint i,j; int tt,q1,q2,q3,q4; sort(ji+1,ji+1+n,cmp_x); for(i=1;i<=n;++i) { tt=er1(ji[i].rx+1,ji[i].ry+1,i+1); for(j=tt;j>i;--j) { if( ji[j].lx!=ji[i].rx+1 || ji[j].ry<ji[i].ly-1 ) break; if(ji[j].ly>ji[i].ry) { if(ji[j].ly==ji[i].ry+1) ++an2; continue; } if(ji[j].ry<ji[i].ly) { if(ji[j].ry==ji[i].ly-1) ++an2; continue; } q1=min(ji[i].ly,ji[j].ly); q2=q1^ji[i].ly^ji[j].ly; q4=max(ji[i].ry,ji[j].ry); q3=q4^ji[i].ry^ji[j].ry; an+=1LL*(q3-q2)*2; if(q1<q2) ++an; if(q4>q3) ++an; } } sort(ji+1,ji+1+n,cmp_y); for(i=1;i<=n;++i) { tt=er2(ji[i].rx+1,ji[i].ry+1,i+1); for(j=tt;j>i;--j) { if( ji[j].ly!=ji[i].ry+1 || ji[j].rx<ji[i].lx-1 ) break; if(ji[j].lx>ji[i].rx) { if(ji[j].lx==ji[i].rx+1) ++an2; continue; } if(ji[j].rx<ji[i].lx) { if(ji[j].rx==ji[i].lx-1) ++an2; continue; } q1=min(ji[i].lx,ji[j].lx); q2=q1^ji[i].lx^ji[j].lx; q4=max(ji[i].rx,ji[j].rx); q3=q4^ji[i].rx^ji[j].rx; an+=1LL*(q3-q2)*2; if(q1<q2) ++an; if(q4>q3) ++an; } } } int main(){ //freopen("T1.in","r",stdin); //freopen("ljh1.in","r",stdin); rint i; read(n); for(i=1;i<=n;++i) { read(ji[i].lx); read(ji[i].ly); read(ji[i].rx); read(ji[i].ry); an=an+1LL*(ji[i].ry-ji[i].ly)*(ji[i].rx-ji[i].lx)*2; } work(); cout<<an+an2/2; }
T2
這個題要在每個節點維護一個map記錄子樹裏每種顏色第一次出現的時間戳
一顆動態開點的以時間戳為下標的線段樹來記錄每一段時間的顏色種數
我們先來考慮如果一次操作對一個節點有貢獻,要滿足兩個條件
1.這次操作的時間戳小於等於這個節點的k值所能到的最大時間戳 (dfs序,在用隨便一個可持久化數據結構可以求出區間k大值)
2.這次操作的顏色必須是第一次出現
對於第一個條件,我們先求出dfs序,將每一個操作鋪成一個線段,線段上每一個點都是一個操作
然後建一顆可持久化01trie\主席樹什麽的,求出$limit_x$ 代表x這個子樹放小球能放的最大時間戳
那麽每一個節點的ans就是在這個節點的線段樹$[1,limit_x]$的不同顏色種數
那麽遞歸處理問題
假設已經將x的兒子都處理完了
將信息合並上來就行了
啟發式合並就行了...
#pragma GCC optimize("O2") #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #include <vector> #include <map> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; inline void read(int &x) { x=0; int ff=1; char q=getchar(); while(q<‘0‘||q>‘9‘) { if(q==‘-‘) ff=-1; q=getchar(); } while(q>=‘0‘&&q<=‘9‘) x=x*10+q-‘0‘,q=getchar(); x*=ff; } const int N=100006; int first[N*2],nt[N*2],ver[N*2],e; void addbian(int u,int v) { ver[e]=v; nt[e]=first[u]; first[u]=e++; } int n,m,Q; int maxk[N]; int limit[N],an[N]; int qi[N],ho[N],fa[N],nw,tim[N]; int pos[N]; map<int,int> mp[N]; vector<int> ji[N]; struct seg { int sz; seg *ch[2]; seg(){sz=0;ch[0]=ch[1]=NULL;} inline void pushup() { sz=0; if(ch[0]!=NULL) sz+=ch[0]->sz; if(ch[1]!=NULL) sz+=ch[1]->sz; } }*rt[N]; void addseg(int pos,int vv,int l,int r,seg *&x) { if(x==NULL) x=new seg(); if(l==r) { x->sz+=vv; return ; } int mid=(l+r)>>1; if(pos<=mid) addseg(pos,vv,l,mid,x->ch[0]); else addseg(pos,vv,mid+1,r,x->ch[1]); x->pushup(); } void qqseg(int L,int R,int &an,int l,int r,seg *&x) { if(L>R) return ; if(x==NULL) return ; if(L<=l&&r<=R) { an+=x->sz; return ; } int mid=(l+r)>>1; if(L<=mid) qqseg(L,R,an,l,mid,x->ch[0]); if(mid<R) qqseg(L,R,an,mid+1,r,x->ch[1]); } struct trie { int sum; trie *ch[2]; trie(){ch[0]=ch[1]=NULL;sum=0;} }*root[N]; void addtrie(int order) { root[order]=new trie(); root[order]->sum=root[order-1]->sum+1; trie *pr=root[order-1],*now=root[order]; int tt,i; for(i=30;i>=0;--i) { tt=((tim[order]&(1<<i))>>i); now->ch[tt]=new trie(); now->ch[tt]->sum=pr->ch[tt]->sum+1; now->ch[tt^1]=pr->ch[tt^1]; now=now->ch[tt]; pr=pr->ch[tt]; } } int qqtrie(int l,int r,int k) { if(l>r) return 0; trie *pr=root[l-1],*now=root[r]; int i,ans=0,t0,t1,tt; for(i=30;i>=0;--i) { t0=now->ch[0]->sum-pr->ch[0]->sum; t1=now->ch[1]->sum-pr->ch[1]->sum; if(!t0||!t1) { if(!t0&&!t1) return ans; if(t0) tt=0; else ans|=(1<<i),tt=1; } else { if(t0>=k) tt=0; else ans|=(1<<i),tt=1,k-=t0; } now=now->ch[tt]; pr=pr->ch[tt]; } return ans; } void dfs1(int x) { qi[x]=nw; int i,sz=ji[x].size(); for(i=0;i<sz;++i) tim[++nw]=ji[x][i]; for(i=first[x];i!=-1;i=nt[i]) { if(ver[i]==fa[x]) continue; fa[ver[i]]=x; dfs1(ver[i]); } ho[x]=nw; } void get_limit() { rint i; dfs1(1); root[0]=new trie(); root[0]->ch[0]=root[0]->ch[1]=root[0]; root[0]->sum=0; for(i=1;i<=nw;++i) addtrie(i); for(i=1;i<=n;++i) { if(maxk[i]==0) limit[i]=0; else limit[i]=qqtrie(qi[i]+1,ho[i],maxk[i]); } } map<int,int> :: iterator it; void mer(int x,int y) { int clo; for(it=mp[pos[x]].begin();it!=mp[pos[x]].end();++it) { clo=it->first; if(!mp[pos[y]].count(clo)) mp[pos[y]][clo]=it->second,addseg(it->second,1,1,m,rt[pos[y]]); else if(mp[pos[y]][clo]>it->second) addseg(mp[pos[y]][clo],-1,1,m,rt[pos[y]]),mp[pos[y]][clo]=it->second,addseg(it->second,1,1,m,rt[pos[y]]); } } void dfs(int x) { int i,t1,t2; for(i=first[x];i!=-1;i=nt[i]) { if(ver[i]==fa[x]) continue; dfs(ver[i]); t1=mp[pos[x]].size(); t2=mp[pos[ver[i]]].size(); if(t1>t2) mer(ver[i],x); else mer(x,ver[i]),swap(pos[x],pos[ver[i]]); } qqseg(1,limit[x],an[x],1,m,rt[pos[x]]); } int main(){ //freopen("T2.in","r",stdin); //freopen("T2.out","w",stdout); rint i,j; mem(first,-1); read(n); int tin1,tin2; for(i=1;i<n;++i) { read(tin1); read(tin2); addbian(tin1,tin2); addbian(tin2,tin1); } for(i=1;i<=n;++i) read(maxk[i]); read(m); for(i=1;i<=m;++i) { read(tin1); read(tin2); ji[tin1].push_back(i); if(!mp[tin1].count(tin2)) mp[tin1][tin2]=i,addseg(i,1,1,m,rt[tin1]); } get_limit(); for(i=1;i<=n;++i) pos[i]=i; dfs(1); read(Q); for(i=1;i<=Q;++i) { read(tin1); printf("%d\n",an[tin1]); } }T2
T3
首先將問題轉化成求 每一天$m^n$種情況下的勞累度總和
$$ans=\frac{C_{k}^{j}*(i-1)^{k-j}*m^{n-k}*w_i*(n-k+1)}{m^{n}}$$
i是枚舉這一天的最大值,j是枚舉最大值的個數
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; inline void read(int &x) { x=0; char q=getchar(); while(q<‘0‘||q>‘9‘) q=getchar(); while(q>=‘0‘&&q<=‘9‘) x=x*10+q-‘0‘,q=getchar(); } const int N=506; const int mod=1000000007; ll qpow(ll a,int ci) { ll ans=1; while(ci) { if(ci&1) ans=ans*a%mod; a=a*a%mod; ci>>=1; } return ans%mod; } int n,m,K; int w[N]; ll C[N][N],mi[N][N]; int main(){ //freopen("T3.in","r",stdin); rint i,j; read(n); read(m); read(K); for(i=1;i<=m;++i) read(w[i]); if(n<K) { puts("0"); return 0; } for(i=0;i<=K;++i) { C[i][0]=C[i][i]=1; for(j=1;j<i;++j) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod; } //for(i=0;i<=m;++i) // mi[0][i]=1; mi[0][0]=1; for(i=1;i<=m;++i) { mi[i][0]=1; for(j=1;j<=n;++j) mi[i][j]=mi[i][j-1]*i%mod; } ll an=0; for(i=1;i<=m;++i) for(j=1;j<=K;++j) an=(an+C[K][j]*mi[i-1][K-j]%mod*w[i]%mod)%mod; an=an*mi[m][n-K]%mod*(n-K+1)%mod; an=an*qpow(mi[m][n],mod-2)%mod; cout<<an; }T3
這一天的題好神啊...
10.27 考試