[考試反思]1023csp-s模擬測試84:精妙

一套很奇怪的題。單調性+神仙dp/搜索+隨機化。c++

可是說實在的,思路都很不錯。ide

考場上顯然亂搞沒什麼好說的。函數

雖然說T2剪枝打錯變量名掉了20分。。。spa

 

T1:Smooth3d

暴力各有不一樣,最暴力的想法就是往隊列裏不斷扔。code

有的元素會被扔屢次致使隊列元素過多。blog

像線性篩同樣,從大到小枚舉質因子,保證每一個數只會被最大的質因子篩掉。隊列

 1 #include<cstdio>
 2 #include<queue>
 3 using namespace std;
 4 priority_queue<long long,vector<long long>,greater<long long> >q;
 5 const int P[16]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
 6 int main(){//freopen("ex_smooth1.in","r",stdin);
 7     int k,b;
 8     scanf("%d%d",&b,&k);
 9     q.push(1);
10     k--;
11     while(k--){
12         long long x=q.top();q.pop();
13         for(int i=b;i;--i)if(x%P[i]==0){q.push(x*P[i]);break;}
14             else q.push(x*P[i]);
15     }
16     printf("%lld\n",q.top());
17 }
T80

像蚯蚓同樣,加入隊列有單調性,因此不用優先隊列。it

開b個隊列,每一個隊列i裏存最大質因子是pi的數。io

 1 #include<cstdio>
 2 #include<queue>
 3 using namespace std;
 4 queue<long long>q[16];
 5 const int P[16]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
 6 int b,k;
 7 long long pop_push(){
 8     long long ans=q[1].front(),bp=1;
 9     for(int i=2;i<=b;++i)if(q[i].front()<ans)ans=q[i].front(),bp=i;
10     q[bp].pop();
11     for(int i=b;i>=bp;--i)q[i].push(ans*P[i]);
12     return ans;
13 }
14 int main(){
15     scanf("%d%d",&b,&k);
16     for(int i=1;i<=b;++i)q[i].push(P[i]);
17     k-=2;
18     while(k--)pop_push();
19     printf("%lld\n",pop_push());
20 }
View Code

 

T2:Six

先說暴力?

搜啊,好像沒什麼好說的。

發現每次加入的數的影響只與它含有哪幾種質因子有關。

而後就能夠愉快的搜了。

 1 #include<cstdio>
 2 #define mod 1000000007
 3 #define int long long
 4 int t[7],knd,al[18];long long n,rate[65];
 5 int sch(int p){//if(p<=3)printf("%d\n",p);
 6     int ans=1;
 7     for(int i=1;i<1<<knd;++i){
 8         int cov=0;
 9         for(int j=1;j<p;++j)if(i&al[j])cov++;
10         if(cov>1)continue;
11         al[p]=i;
12         ans=(ans+rate[i]*sch(p+1))%mod;
13     }
14     return ans;
15 }
16 main(){
17     scanf("%lld",&n);
18     for(long long i=2;i*i<=n;++i)if(n%i==0){
19         knd++;
20         while(n%i==0)n/=i,t[knd]++;
21     }if(n!=1)t[++knd]=1;
22     for(int i=1;i<1<<knd;++i){
23         rate[i]=1;
24         for(int j=1;j<=knd;++j)if(i&1<<j-1)(rate[i]*=t[j])%=mod;
25     }
26     printf("%lld\n",sch(1)-1);
27 }
T74

%%%ParisB的Six的狀態定義。

首先咱們能夠發現,每一個質因子的第一次被加入,至多會分6批。

咱們考慮加入一個數的限制。

若是某一種因子已經被兩個數包含,你還含有這個因子,就不合法。

若是你含有兩個因子A和B,A和B被加入不在同一個數裏(就是我上面說的「6批」),那麼不合法。

若是在同一批裏,那麼你就只與那一批的一個數衝突,仍是合法的。

因此你就記錄一下每個因子是在第幾批加入的。8進制壓位。

0:未被加入。

1~6:被在第1~6批加入。

7:已經被加入2次。

而後對於每一種狀態,枚舉$2^6$種可能的轉移,不合法的狀況只有上面2種。

總複雜度$2^{18} \times 2^6 \times 6$然而由於合法狀態只有2100種,因此最終的複雜度大約是1e6的。

代碼極短可是不易壓行(不然邏輯極其混亂)

適度的經常使用位運算宏定義能使代碼更加簡單而清晰

 1 #include<cstdio>
 2 #define mod 1000000007
 3 #define s1 (k&1<<p-1)
 4 #define s2 (j>>3*p-3&7)
 5 int dp[266666],t[7],cnt,ans;long long n,rate[66];
 6 int main(){
 7     scanf("%lld",&n);
 8     for(long long i=2;i*i<=n;++i)if(n%i==0){
 9         cnt++;
10         while(n%i==0)n/=i,t[cnt]++;
11     }if(n!=1)t[++cnt]=1;
12     for(int i=1;i<1<<cnt;++i){
13         rate[i]=1;
14         for(int j=1;j<=cnt;++j)if(i&1<<j-1)rate[i]*=t[j];
15     }
16     dp[0]=1;
17     for(int j=0;j<1<<cnt*3;++j)if(dp[j]){
18         ans=(ans+dp[j])%mod;
19         for(int k=1;k<1<<cnt;++k){
20             int x=0,ns=j,m=0;
21             for(int p=1;p<=cnt;++p)if(!s2&&s1){x=p;break;}
22             for(int p=1;p<=cnt;++p)if(s2&&s1)
23                 if(s2==7)goto F;
24                 else if(!m)m=s2;
25                 else if(m!=s2)goto F;
26             for(int p=1;p<=cnt;++p)if(s1)
27                 if(s2)ns|=7<<3*p-3;
28                 else ns|=x<<3*p-3;
29             dp[ns]=(dp[ns]+dp[j]*rate[k])%mod; F:;
30         }
31     }printf("%d\n",ans-1);
32 }
825B。快去%ParisB

 

T3:Walker

變化完以後的最終座標是$(scale \ cos \theta \ x - scale\  sin \theta \ y +d_x,scale \ sin \theta\ x + scale \ cos\theta \ y +d_y)$

咱們把$scale \ sin \theta$和$scale \ cos \theta$看作兩個單獨的變量,叫$a,b$吧

而後咱們隨便帶兩組數據進去就能解出$a,b,d_x,d_y$這四個變量

根據$sin^2\theta +cos^2\theta=1$,獲得$a^2+b^2=scale^2$

因此咱們就解出了$scale$,同時也就解出了$sin\theta$和$cos\theta$

而後問題在於怎麼解出$\theta$。方法不少,我說一個。

根據$\frac{sin\theta}{cos\theta}=tan\theta$咱們能知道$tan$值,利用$atan$函數獲得一個$\theta$值。

而後咱們再用$sin$函數算一下這個$\theta$的正弦值和上面那個$\frac{a}{scale}$是否一致。

若是一致,那麼就對了,不然加一個$\pi$,轉半圈就是了。(由於只根據$tan$獲得的角度值可能恰好是相反的)

咱們對於兩個座標求出的一組解拿去check,若是超過半數都是對的那麼就完事,不然繼續循環

由於有一半是正確的,因此你選出兩個正確座標的機率是$\frac{1}{4}$,不是很小,因此循環不會不少次。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ldb double
 4 int n;ldb x[100005],y[100005],_x[100005],_y[100005],mxt[5][6];
 5 void Gauss(){
 6     for(int i=1;i<=4;++i){
 7         ldb mx=mxt[i][i];int mxp=i;
 8         for(int j=i+1;j<=4;++j)if(fabs(mxt[j][i])>mx)mx=fabs(mxt[j][i]),mxp=j;
 9         if(mxp!=i)for(int j=i;j<=5;++j)swap(mxt[i][j],mxt[mxp][j]);
10         for(int j=4;j>i;--j)for(int k=5;k>=i;--k)mxt[j][k]-=mxt[j][i]/mxt[i][i]*mxt[i][k];
11     }
12     for(int i=4;i;--i)for(int j=i-1;j;--j)mxt[j][5]-=mxt[i][5]*mxt[j][i]/mxt[i][i];
13     for(int i=4;i;--i)mxt[i][5]/=mxt[i][i];
14 }
15 int main(){
16     scanf("%d",&n);srand(time(0));
17     for(int i=1;i<=n;++i)scanf("%lf%lf%lf%lf",&_x[i],&_y[i],&x[i],&y[i]);
18     while(1){
19         int p1=rand()%n+1,p2=rand()%n+1,AC=0;
20         while(p1==p2)p2=rand()%n+1;
21         mxt[1][5]=x[p1];mxt[1][4]=0;mxt[1][3]=1;mxt[1][2]=-_y[p1];mxt[1][1]=+_x[p1];
22         mxt[2][5]=y[p1];mxt[2][4]=1;mxt[2][3]=0;mxt[2][2]=+_x[p1];mxt[2][1]=+_y[p1];
23         mxt[3][5]=x[p2];mxt[3][4]=0;mxt[3][3]=1;mxt[3][2]=-_y[p2];mxt[3][1]=+_x[p2];
24         mxt[4][5]=y[p2];mxt[4][4]=1;mxt[4][3]=0;mxt[4][2]=+_x[p2];mxt[4][1]=+_y[p2];
25         Gauss();
26         ldb scale=mxt[1][5]*mxt[1][5]+mxt[2][5]*mxt[2][5];scale=sqrt(scale);
27         ldb cosine=mxt[1][5]/scale,sine=mxt[2][5]/scale,theta=atan(sine/cosine),X=mxt[3][5],Y=mxt[4][5];
28         if(scale>10||scale<0)continue;
29         if(fabs(sin(theta)-sine)>1e-7)theta+=3.141592653589793238462643383279l;
30         if(theta<-1e-8)theta+=3.141592653589793238462643383279L*2;
31         for(int i=1;i<=n;++i)if(fabs(scale*cos(theta)*_x[i]-scale*sin(theta)*_y[i]+X-x[i])<1e-4&&fabs(scale*sin(theta)*_x[i]+scale*cos(theta)*_y[i]+Y-y[i])<1e-4)AC++;
32         if(AC>=n+1>>1)return printf("%.18lf\n%.18lf\n%.18lf %.18lf\n",theta,scale,X,Y),0;
33     }
34 }
View Code
相關文章
相關標籤/搜索