[考試反思]1217省選模擬1: 苟且


的確扛過了聯賽,然后貌似也做好了心理准備。

但是這。。。

再加上聯賽的先天劣勢。。。

先不用說翻盤,好歹省選跟別人追平,才有資格談翻盤吧?

(然而其實就算追平了也沒資格,還差十幾分)

省選這個難度,追十幾分。。。

最近煩心的事是真的多。。。扛過這一段,也許一切都會好起來吧。。。

 

省選模擬4個小時,並沒有想象中那么漫長。

難度預估全錯:T2<T1<T3。與現在所認為的難度順序,只是大於號全部想成了小於號。。。

然后自然,時間分配就全亂了。

看到T3樹論?還放在T3的位置上?啥還NPC了?大神題不敢做,然后就丟掉了唯一一個可能想出來的題。

坐在我右邊的三個大神都切了我給我這一排丟人了2333

然后就一直在找T1和T2的規律。

剛開始T1還沒看到保證P是質數白YY了半天。

后來在想的時候,想到指數肯定不能直接算,所以應該要用原根。然后想了一會腦子里萌生了一個想法:

不是所有的質數都有原根!

然后我就歇比了我也不知道我是怎么想的反正這個“靈光一現”就幫助T1把我切了。

T2顯然是找不出來規律的,但是我花費了大量的時間。。。然后寫的搜索懶得打剪枝就丟了10分。

懶得打。。。?其實我算了一下復雜度,差不多是對了就扔了,,然而並沒有發現無良玩意有1000組測試數據。。。

過了一會離考試結束還有20分鍾發現T1的20分暴力貌似會TLE0,急忙修改,改的時候靈感突現順手寫了個40分的不會證算法。

發現這個很適合打表,但是還有十幾分鍾。。?

最后就拿到了這個啥也不是的成績。

希望明天不要這么蠢了。。。關鍵是要靜下心來。。。

題是真的難,而且部分分的確沒什么區分度(基本所有人都想的出來而且分值小),所以還是要沖着正解去不然3道題加起來才100分玩個啥啊。。。

 

T1:天空碎片

題意:求$1<=n,m<=P(P-1)$滿足$n^m \equiv m^n (mod \ P)$。數據范圍:$P \le 10^{12} $。答案對給定模數取模。100組測試數據。

一看到題目里那個P(P-1)就知道事情一定不簡單。對於一個冪,底數可以對p取模,指數可以對(p-1)取模。

所以P(P-1)就會剛好取遍每一個底數/指數值一次,我們只要統計這樣的值對P取模后有多少種放進桶里,平方后就是對答案的貢獻。

 1 #include<cstdio>
 2 #define int long long
 3 int mod,x,buc[1111];
 4 main(){
 5     int t,ans;
 6     scanf("%lld%lld",&t,&mod);
 7     while(t--){ans=0;
 8         scanf("%lld",&x);
 9         for(int i=0,w=1;w=1,i<x;++i)for(int j=0;j<x-1;++j,w=w*i%x)buc[w]++;
10         buc[0]++;buc[1]--;
11         for(int i=0;i<x;++i)ans+=buc[i]*buc[i]%mod,buc[i]=0;
12         printf("%lld\n",ans%mod);
13     }
14 }
40分暴力

然后代入原根,問題轉化為問有多少數對(a,b,c,d)滿足$ab \equiv cd (mod \ P-1)$,其中$0 \le a,b,c,d < P-1$。在這里沒有考慮i和j直接是P的倍數。

含義?就是原根的指數取模后相同,然后就同余了啊。

可以發現,可以CRT掉把問題分解為質數層面,答案相乘,因為根據兩個互質數點對一定可以得到一個在它們條件下都滿足的點對。

設上面所說的這個定義為函數F(P-1),現在已經分解為$\prod F(p_i^{e_i})$

對於一個質數的冪求解,問題就是看模x之后ab的取值。設$C(i)$為$ab \equiv i$的ab對數。

然后既然是對質數考慮,那么我們就把abi都對p分解。枚舉它們分別含有p的幾次冪

太累了粘題解了。其中C(0)那一項看着簡單實際要化大量的式子。要考慮a'或b'為0的情況再加>=e的情況,再拼湊式子。

就是分別枚舉alpha和beta,保證它們的和大於e,再動用等比數列求和拆和式,最后就是一波因式分解+合並同類項。

然后根據含義$ F(p_i^{e_i})=\sum\limits_{i=0}^{p_i^{e_i}-1} C^2(i)$

然后得到答案$ans=(P-1)^2 + F(P-1)$。在這里又一次考慮了整除的ab。

挺惡心的。注意取模。

 1 #include<cstdio>
 2 #define int long long
 3 int t,mod,P,pr[22],E[22],pc,phi[22];
 4 int pow(int b,int t,int a=1){for(;t;t>>=1,b=b*b%mod)if(t&1)a=a*b%mod;return a;}
 5 main(){
 6     scanf("%lld%lld",&t,&mod);
 7     while(t--){
 8         scanf("%lld",&P);P--;int rp=P%mod;pc=0;
 9         for(int i=2;i*i<=P;++i)if(P%i==0){
10             pr[++pc]=i;E[pc]=0;phi[pc]=1;
11             while(P%i==0)P/=i,E[pc]++,phi[pc]*=i;
12             phi[pc]=phi[pc]/i*(i-1)%mod;
13         }if(P!=1)pr[++pc]=P,E[pc]=1,phi[pc]=(P-1)%mod;
14         int ans=1;
15         for(int i=1,p,e;p=pr[i],e=E[i],i<=pc;++i){
16             int w=pow(phi[i]*(e+1)%mod+pow(p,e-1),2);
17             for(int j=0;j<e;++j)w=(w+pow(p,e-j-1)*(p-1)%mod*pow((j+1)*phi[i]%mod,2))%mod;
18             ans=ans*w%mod;
19         }
20         printf("%lld\n",(ans+rp*rp)%mod);
21     }
22 }
View Code

 

T2:未來拼圖

題意:長度為N的對稱整數數列循環卷積得到數列F,給定F求原數列個數及字典序最小的方案。$N \le 25 ,T \le 1000$

需要比較深刻的理解DFT,而不是直接跳過它得到FFT。

可以認為,DFT處理的本質問題就是循環卷積(詳見Cage的證明),而FFT把長度開成了兩倍來防止超出部分循環回去。

所以只需要做1倍長度的DFT得到點值,點值開根得到插值,判斷方案是否合法即可。

當然長度才25,暴力$O(n^2)$的插值求值就可以了,寫FFT常數可能反而更大。。。

而在開根時每個復數(除0外)都有2個根,要枚舉到所有情況。而因為數列是對稱的,所以只需要確定其中一側的復數取值就可以確定另一側。

可能會卡常。把所有單位復數根都預處理出來就飛快了。

總復雜度$O(T 2^{\frac{N}{2} +1} N^2)$。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 map<vector<int>,int>M;
 4 vector<int>v;
 5 const double eps=1e-5,pi=3.141592653589793238;
 6 struct cp{
 7     double r,i;
 8     cp(double re=0,double im=0){r=re;i=im;}
 9     cp operator+(cp b){return cp(r+b.r,i+b.i);}
10     cp operator-(cp b){return cp(r-b.r,i-b.i);}
11     cp operator*(cp b){return cp(r*b.r-i*b.i,r*b.i+i*b.r);}
12     void operator=(int x){r=x;i=0;}
13     cp sqrt(){
14         if(fabs(r)<eps&&fabs(i)<eps)return cp(0,0);
15         double alpha=atan2(i,r)/2,len=std::sqrt(std::sqrt(r*r+i*i));
16         return cp(cos(alpha)*len,sin(alpha)*len);
17     }
18 }A[27],P[27],B[27],C[27],R[27],Q[27],W[27][27][27];
19 int t,n,cnt,r[27],c[27];
20 void DFT(cp*A,cp*B,int n){
21     for(int i=0;i<n;++i)B[i]=0;
22     for(int i=0;i<n;++i){
23         cp w=cp(cos(pi*2/n*i),sin(pi*2/n*i)),t=cp(1,0);
24         for(int j=0;j<n;++j)B[i]=B[i]+A[j]*t,t=t*w;
25     }
26 }
27 void IDFT(cp*A,cp*B,int n){
28     for(int i=0;i<n;++i)B[i]=0;
29     for(int i=0;i<n;++i)for(int j=0;j<n;++j)B[i]=B[i]+A[j]*W[n][i][j];
30     for(int i=0;i<n;++i)B[i].r/=n,B[i].i/=n;
31 }
32 void update(){
33     for(int i=0;i<n;++i)if(c[i]>r[i])break;else if(c[i]<r[i])return;
34     for(int i=0;i<n;++i)c[i]=r[i];
35 }
36 main(){
37     scanf("%d",&t);
38     for(int n=0;n<=25;++n)for(int i=0;i<n;++i)for(int j=0;j<n;++j)W[n][i][j]=cp(cos(-pi*2/n*i*j),sin(-pi*2/n*i*j));
39     while(t--){
40         scanf("%d",&n);cnt=0;c[0]=12346567;
41         for(int i=0,x;i<n;++i)scanf("%d",&x),P[i]=x;
42         DFT(P,A,n);
43         for(int i=0;i<n;++i)B[i]=A[i].sqrt(),C[i]=cp(-B[i].r,-B[i].i);
44         for(int i=0;i<1<<n/2+1;++i){
45             for(int j=0;j<n/2+1;++j)if(i&1<<j)R[j]=B[j],R[n-j]=B[n-j];else R[j]=C[j],R[n-j]=C[n-j];
46             IDFT(R,Q,n);
47             for(int j=0;j<n;++j)if(floor(Q[j].r-eps)==floor(Q[j].r+eps))goto fail;else r[j]=floor(Q[j].r+eps);
48             for(int j=1;j<n;++j)if(r[j]!=r[n-j]||r[j]<0)goto fail;
49             if(r[0]<0)goto fail;
50             v.clear();for(int i=0;i<n;++i)v.push_back(r[i]);
51             if(M.find(v)!=M.end())continue;M[v];
52             cnt++;update();fail:;
53         }
54         printf("%d ",cnt);if(cnt)for(int i=0;i<n;++i)printf("%d ",c[i]);puts("");M.clear();
55     }
56 }
View Code

 

T3:完美理論

題意:(假裝是個NPC問題)給兩棵樹,點編號相同權值相同,要求選出一個最大權點集在兩棵樹上都是聯通塊。$n\le 100,T \le 50$

所以它並不是NPC,也並不是樹論,也並不是dp。

當我們考慮一個點集時,發現它有一定依賴關系。

兩棵樹都是無根的,我們欽定一個根,如果保證根必選,那么就必須有「選了兒子就必須選父親」的限制。

枚舉根,跑最大權閉合子圖。

我為什么會慫這個題啊。。。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int fir[102],l[202],to[202],FIR[102],L[202],TO[202],n,t,w[102],ec,EC,ans;
 4 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;}
 5 void Link(int a,int b){L[++EC]=FIR[a];FIR[a]=EC;TO[EC]=b;}
 6 int wfir[102],wl[888],wto[888],ww[888],Ec,q[111],d[111];
 7 void wlink(int a,int b,int W){wl[++Ec]=wfir[a];wfir[a]=Ec;wto[Ec]=b;ww[Ec]=W;}
 8 void con(int a,int b,int W){wlink(a,b,W);wlink(b,a,0);}
 9 void dfs(int p,int fa){for(int i=fir[p];i;i=l[i])if(to[i]!=fa)con(to[i],p,10000000),dfs(to[i],p);}
10 void DFS(int p,int fa){for(int i=FIR[p];i;i=L[i])if(TO[i]!=fa)con(TO[i],p,10000000),DFS(TO[i],p);}
11 bool bfs(){
12     for(int i=1;i<=n+1;++i)d[i]=0;d[0]=1;
13     for(int h=1,t=1;h<=t;++h)for(int i=wfir[q[h]];i;i=wl[i])if(!d[wto[i]]&&ww[i])
14         d[q[++t]=wto[i]]=d[q[h]]+1;
15     return d[n+1];
16 }
17 int dinic(int p,int flow){int r=flow;
18     if(p==n+1)return r;
19     for(int i=wfir[p];i&&r;i=wl[i])if(ww[i]&&d[wto[i]]==d[p]+1){
20         int x=dinic(wto[i],min(r,ww[i]));
21         if(!x)d[wto[i]]=0;
22         ww[i]-=x;ww[i^1]+=x;r-=x;
23     }return flow-r;
24 }
25 int main(){
26     scanf("%d",&t);
27     while(t--){
28         scanf("%d",&n);ans=0;
29         for(int i=1;i<=n;++i)fir[i]=FIR[i]=0;ec=EC=0;
30         for(int i=1;i<=n;++i)scanf("%d",&w[i]);
31         for(int i=1,x,y;i<n;++i)scanf("%d%d",&x,&y),link(x,y),link(y,x);
32         for(int i=1,x,y;i<n;++i)scanf("%d%d",&x,&y),Link(x,y),Link(y,x);
33         for(int i=1;i<=n;++i){
34             for(int j=0;j<=n+1;++j)wfir[j]=0;Ec=1;int mx=0;
35             for(int j=1;j<=n;++j)if(w[j]>0)con(0,j,w[j]),mx+=w[j];else con(j,n+1,-w[j]);
36             dfs(i,0);DFS(i,0);while(bfs())mx-=dinic(0,10000000);
37             ans=max(ans,mx);
38         }
39         printf("%d\n",ans);
40     }
41 }
View Code


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM