[考試反思]1018csp-s模擬測試79:荒謬

對,若是你想把第5名粘進來,那麼圖片就是這麼誇張。ios

然而和我並無什麼關係,實在是太菜了。ide

可是仍是想吐槽出題人是真心沒良心啊。。。作了達哥的良心題以後眼光極其挑剔spa

這套題的部分分設置很是愚蠢,惟一一個可用的部分分在T2,可是T2說的還很不清楚。3d

T2其實已經完成了最艱難的轉化題意,可是最後敗在了細節上。code

T1也基本上是全場切,結果出鍋了。blog

 

我想問一個問題啊:在時間比較緊的狀況下,是應該打完題就打對拍,仍是優先往下作題啊?圖片

 

skyh就是沒臉。去廁所遇到他的話我這場絕對炸。ci

發現T2題意前遇到的qt

我:我估計我60分it

FACEFACE:那我確定不止60分了。我發現T2的題意了,難題。

而後我差點就棄T2了,差點就只剩下50分了。。。

 

T1暴力彈棧暴力恢復,結果恢復的時候往棧裏應該是倒序加,而不該該是正序。。。掛70

T2計算$C_n^3$時沒除6鍋了20分。

。。。

心情稍低沉。愈加感受本身像個傻子。

會題不必定不是傻子。

拿不到分那就是個傻子。。。

吸收教訓吧。。。

對拍。要對拍。就你那個程度不打對拍確定鍋。

 

T1:樹

由於我蠢因此沒想到正解。考場上維護了一個單調棧,而後離線暴幹。

會被蒲公英圖/掃帚圖幹掉成$O(n^2)$。可是出題人保證數據隨機。我沒打正解我沒臉。

正解很簡單,按照遞減序建樹,倍增亂搞就行。沒心情打了。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<vector>
 5 using namespace std;
 6 vector<int>anc[100005],c[100005],id[100005],tmp[100005];
 7 int fir[100005],l[200005],to[200005],cnt,n,q,w[100005],dep[100005];
 8 int sta[100005],top,sdep[100005],sw[100005],ans[100005];
 9 void link(int a,int b){l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;}
10 bool com(int a,int b){return a>b;}
11 void dfs(int p,int fa){
12     dep[p]=dep[fa]+1;
13     while(top&&sw[top]<=w[p])top--,tmp[p].push_back(sta[top+1]);
14     sta[++top]=p;sw[top]=w[p];sdep[top]=dep[p];
15     for(int i=0;i<id[p].size();++i){
16         int ed=lower_bound(sw+1,sw+1+top,c[p][i],com)-sw,st=lower_bound(sdep+1,sdep+1+top,dep[anc[p][i]])-sdep;
17         ans[id[p][i]]=max(0,ed-st);
18     }
19     for(int i=fir[p];i;i=l[i])if(to[i]!=fa)dfs(to[i],p);
20     top--;
21     for(int i=(int)tmp[p].size()-1;~i;--i)sta[++top]=tmp[p][i],sw[top]=w[sta[top]],sdep[top]=dep[sta[top]];
22 }
23 int main(){
24     scanf("%d%d",&n,&q);
25     for(int i=1;i<=n;++i)scanf("%d",&w[i]);
26     for(int i=1,x,y;i<n;++i)scanf("%d%d",&x,&y),link(x,y),link(y,x);
27     for(int i=1,u,v,C;i<=q;++i)scanf("%d%d%d",&u,&v,&C),anc[u].push_back(v),c[u].push_back(C),id[u].push_back(i);
28     dfs(1,0);
29     for(int i=1;i<=q;++i)printf("%d\n",ans[i]);
30 }
View Code

 

T2:環circle

其實雖然說題目說的很不清楚,可是仍是有不少提示的。

能從題目裏隱隱約約得出如下信息:

競賽圖,環,最小。

看一眼數據範圍,最小暴力分是n=300。這個只能是$O(n^3)$的複雜度了。

再把第一個樣例的16個圖都畫出來,不難發現它要的就是三元環計數,不分起點。

求證:競賽圖若是有環,那麼最小環必定是三元環

證實:

若是存在一個大於3元的環,那麼對於其中任意距離大於等於2的兩個點ab,在環上已經存在了一個順時針和一個逆時針路徑。

這時候由於圖是競賽圖,ab兩點之間也必須直接有邊,這一條邊能和順時針路徑或逆時針路徑之一造成一個環。

這個環小於原來的環。這樣的話大環會不斷被分割成小的。直到環中不存在距離大於等於2的點,那麼就只剩下了一個三元環。

證畢。

那麼就是求三元環數量了。

30分:n<=300。

暴力枚舉三個點。看貢獻。

若是你一條邊都不知道,那麼可能造成2種環,一共$2^3=8$種狀況,指望貢獻1/4。

若是你只知道一條邊,那麼只能造成1種環,一共$2^2=4$種狀況,指望貢獻1/4。

若是你知道兩條邊,這兩條邊指向或背向同一個點,那麼貢獻是0,不然貢獻1/2。

若是你三條邊都知道。。。那就不用我說了吧。。。貢獻0或1

+20分:e=0

全都是三條邊都不知道的狀況,是$\frac{1}{4} \times C_n^3$

+20分:e=n*(n-1)/2

全都是三條邊都知道的狀況,可是不能$n^3$枚舉。

由於e<=1000000,因此能夠知道n<=1500。

bitset枚舉(也能夠不用)。大力討論。

100分:

考慮容斥。先讓全部邊都產生貢獻。

而後產生負貢獻的就是不合法的三元環:有兩條邊從同一個點指出。

而後考慮指望有多少這樣的環。

枚舉全部這樣的點,考慮每一條不肯定的邊。

若是$p_i$表示這個點i有幾條出邊,有$q_i$條未知邊。

答案減去$C_{p_i}^2 + \frac{C_{q_i}^2}{4} + \frac{p_i \times q_i}{2}$

 1 //能夠證實,競賽圖只要存在環,那麼最小的環大小必定是3
 2 //因此問的就是圖中指望有幾個三元環
 3 #include<cstdio>
 4 #include<vector>
 5 using namespace std;
 6 vector<int>in[1555],out[1555];
 7 #define qtr 250000002ll
 8 #define hlf 500000004ll
 9 #define mod 1000000007ll
10 int pow(long long b,int t,long long a=1){for(;t;t>>=1,b=b*b%mod)if(t&1)a=a*b%mod;return a;}
11 int graph[1555][1555],n,e;long long ans;
12 int main(){
13     scanf("%d%d",&n,&e);
14     if(e==0){
15         printf("%lld\n",qtr*n%mod*(n-1)%mod*(n-2)%mod*pow(6,mod-2)%mod);
16     }else if(n<=300){
17         for(int i=1,x,y;i<=e;++i)scanf("%d%d",&x,&y),graph[x][y]=1,graph[y][x]=-1;
18         for(int i=1;i<=n;++i)for(int j=i+1;j<=n;++j)for(int k=j+1;k<=n;++k)
19             if((graph[i][j]!=0)+(graph[j][k]!=0)+(graph[i][k]!=0)<=1)ans+=qtr;
20             else if(graph[i][j]==1&&graph[j][k]==1&&graph[k][i]==1)ans++;
21             else if(graph[i][j]==-1&&graph[j][k]==-1&&graph[k][i]==-1)ans++;
22             else if(graph[i][j]==1&&graph[j][k]==1&&graph[k][i]==0)ans+=hlf;
23             else if(graph[i][j]==-1&&graph[j][k]==-1&&graph[k][i]==0)ans+=hlf;
24             else if(graph[i][j]==1&&graph[j][k]==0&&graph[k][i]==1)ans+=hlf;
25             else if(graph[i][j]==-1&&graph[j][k]==0&&graph[k][i]==-1)ans+=hlf;
26             else if(graph[i][j]==0&&graph[j][k]==1&&graph[k][i]==1)ans+=hlf;
27             else if(graph[i][j]==0&&graph[j][k]==-1&&graph[k][i]==-1)ans+=hlf;
28         printf("%lld\n",ans%mod);
29     }else if(e<<1==n*(n-1ll)){
30         for(int i=1,x,y;i<=e;++i)scanf("%d%d",&x,&y),graph[x][y]=1;
31         for(int i=1;i<=n;++i)for(int j=i+1;j<=n;++j)if(graph[i][j])out[i].push_back(j);else in[i].push_back(j);
32         for(int i=1;i<=n;++i)for(int j=0;j<out[i].size();++j)for(int k=0;k<in[i].size();++k)ans+=graph[out[i][j]][in[i][k]];
33         printf("%lld\n",ans%mod);
34     }
35 }
部分分打滿
 1 //能夠證實,競賽圖只要存在環,那麼最小的環大小必定是3
 2 //因此問的就是圖中指望有幾個三元環
 3 #include<cstdio>
 4 #include<vector>
 5 using namespace std;
 6 #define qtr 250000002ll
 7 #define hlf 500000004ll
 8 #define six 166666668ll
 9 #define mod 1000000007ll
10 int pow(long long b,int t,long long a=1){for(;t;t>>=1,b=b*b%mod)if(t&1)a=a*b%mod;return a;}
11 int p[100005],q[100005],n,e;long long ans;
12 int main(){
13     scanf("%d%d",&n,&e);
14     ans=1ll*n*(n-1)%mod*(n-2)%mod*six%mod;
15     for(int i=1,x,y;i<=e;++i)scanf("%d%d",&x,&y),p[x]++,q[y]--,q[x]--;
16     for(int i=1;i<=n;++i)q[i]+=n-1;
17     for(int i=1;i<=n;++i)ans=(ans-p[i]*(p[i]-1ll)/2-1ll*p[i]*q[i]%mod*hlf%mod-q[i]*(q[i]-1ll)/2%mod*qtr%mod+mod)%mod;
18     printf("%lld\n",ans);
19 }
AC

 

T3:禮物gift

$C_{a_i + b_i + a_j + b_j}^{a_i + a_j}$

$=\sum\limits_{t=0}^{a_i + a_j}C_{a_i +b_i}^{t} \times C_{a_j + b_j}^{a_i + a_j -t}$

$=\sum\limits_{t=-a_i}^{a_j}C_{a_i +b_i}^{t + a_i} \times C_{a_j + b_j}^{a_j -t}$

$=\sum\limits_{t=-a_i}^{b_i}C_{a_i +b_i}^{t + a_i} \times C_{a_j + b_j}^{a_j -t}$

而後就能夠發現兩部分式子已經分別只與i和j有關了。

帶j的那一項關於t開一個桶,而後每次加一個新物品時先枚舉t查找桶裏的值,再往桶裏放一下。

注意貢獻答案時t的枚舉範圍與更新桶時的t的枚舉範圍是徹底相反的。

拆開兩部分分別算,改變枚舉範圍。這是這道題的難點。

 1 #include<cstdio>
 2 #define mod 1000000007
 3 int fac[20000005],invv[20000005],inv[20000005],n,BUC[40000005],*buc=BUC+20000002,ans;
 4 int Mod(int p){return p<mod?p:p-mod;}
 5 int C(int b,int t){return (t<0||t>b)?0:1ll*fac[b]*inv[b-t]%mod*inv[t]%mod;}
 6 main(){
 7     fac[0]=fac[1]=invv[1]=inv[0]=inv[1]=1;
 8     for(int i=2;i<=20000000;++i)fac[i]=1ll*fac[i-1]*i%mod,invv[i]=mod-1ll*mod/i*invv[mod%i]%mod,inv[i]=1ll*inv[i-1]*invv[i]%mod;
 9     scanf("%d",&n);
10     for(int i=1,a,b;i<=n;++i){
11         scanf("%d%d",&a,&b);
12         for(int t=-a;t<=b;++t)ans=Mod(ans+1ll*buc[-t]*C(a+b,a+t)%mod);
13         for(int t=-b;t<=a;++t)buc[-t]=Mod(buc[-t]+C(a+b,a-t));
14     }printf("%d\n",Mod(ans<<1));
15 }
View Code
相關文章
相關標籤/搜索