3.18省選模擬
$T1$
大概就是找一個最小的半徑,使得生成的橢圓能包含所有點
首先由於生成橢圓不是水平的,可以考慮先把每個點順時針旋轉然後讓橢圓的長半軸轉到$x$軸上
然後把$x$軸縮放就好了,考慮一下,我們現在有一個橢圓包含了所有點,那麼我們僅僅需要一個相對關係,那麼當$x$都縮放之後,最小橢圓仍然滿足條件,並且長度成為原來的$\frac{1}{p}$,到現在就是找一個最小的圓能夠覆蓋所有的點了
然後跑一個最小圓覆蓋就好了
最小圓覆蓋,可以用隨機增量法,就是我們現在已經已經得到了前$i-1$個點的外接圓
這個時候我們新加入一個點$i,$這個時候需要得到一個新的外接圓
如果這個時候$i$已經在外接圓裡了,就直接$continue,$顯然這個圓不能增大或變小,如果不在圓內
首先這個點必然在圓上如果不在圓上的話,就說明原來的點形成的圓可以包含它,不成立
那麼我們現在有了圓上的一點,我們就可以列舉另外兩點來三點確定一個圓
大概過程就是,先把圓心定到$i$點,然後列舉第二個點,確定圓心和半徑,最後列舉第三個點求個外接圓(把所有點都包含)就好了
表面複雜度是$n^3$,均攤$O(n)$不知道為什麼...
#include<bits/stdc++.h> #define MAXN 1000005 using namespace std; const double PI=acos(-1); struct vec { double x,y; }poz[MAXN];double du,r,p; int n; double Dis(vec A,vec B) { return sqrt(pow(A.x-B.x,2)+pow(A.y-B.y,2)); } vec SDY(vec A,vec B,vec C) { double a=A.x-B.x; double b=A.y-B.y; double c=A.x-C.x; double d=A.y-C.y; a*=-1; b*=-1; c*=-1; d*=-1; double e=(pow(A.x,2)-pow(B.x,2)-pow(B.y,2)+pow(A.y,2))/2; double f=(pow(A.x,2)-pow(C.x,2)-pow(C.y,2)+pow(A.y,2))/2; return (vec){(d*e-b*f)/(b*c-a*d),(a*f-c*e)/(b*c-a*d)}; } vec rtt(vec a,double altha) { altha*=-1; return (vec){a.x * cos(altha) - a.y * sin(altha),a.x * sin(altha) + a.y *cos(altha)}; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lf%lf",&poz[i].x,&poz[i].y); } scanf("%lf%lf",&du,&p); for(int i=1;i<=n;i++) { poz[i]=rtt(poz[i],du/180.0*PI); poz[i].x/=p; } random_shuffle(poz+1,poz+1+n); vec yuan; yuan.x=0,yuan.y=0; double r2=0,nx,ny; for(int i=1;i<=n;i++) { if(Dis(poz[i],yuan)>r) { yuan=poz[i]; r=0; //其實這一步我們是確定第二個點的位置 //我們就是列舉三個點使他構成圓 //如果沒有包含所有點就重構 for(int j=1;j<i;j++) { if(Dis(yuan,poz[j])>r) { yuan.x=(poz[i].x+poz[j].x)/2.0; yuan.y=(poz[i].y+poz[j].y)/2.0; r=Dis(poz[i],poz[j])/2.0; //並不是很理解這一步有什麼用 for(int k=1;k<j;k++) { if(Dis(poz[k],yuan)>r) { yuan=SDY(poz[i],poz[j],poz[k]); r=Dis(poz[k],yuan); } } } } } } printf("%.3f",r); }
$T2$
列舉一條直線把集合分成兩個部分
顯然每種情況都是不重不漏的被計算進去了,而且所有的情況都可以由一條直線化成兩個集合來計算
那麼就列舉直線來計算方案,就是說分成兩個集合後必然界限分明,那麼就可以列舉界限計算了
$T3$
迴文自動機
其實就是求另一個串和另一個串的最長公共迴文串
迴文自動機$PAM$
從學了之後一直沒有用過的科技
迴文自動機的構造
奇根和偶根
奇根的編號$0,fail$指向奇根
偶根的編號$1,fail$指向自身
其實和$AC$自動機一樣,我們$AC$自動機能識別所有的迴文串
$fail$指標也就是相當於$AC$自動機上的最長公共字尾一樣,這個表示的是最長迴文字尾
然後每一條路徑都表示一個原字串的一個迴文串,其實這個就相當於把字串的所有子串都插進去就好了
感覺這個有種既像$AC$自動機又像$SAM$的感覺
我們每次插入一個新節點,就是一直跳$fail$找到能識別他這個節點為字尾節點的迴文串就好了
#include<bits/stdc++.h> #define MAXN 11000000 using namespace std; char s[MAXN]; int fail[MAXN],len[MAXN],num[MAXN],tr[MAXN][30],ls=0,now=0,tot=1; int get(int i,int x) { while(i-len[x]-1<0||s[i-len[x]-1]!=s[i]) x=fail[x]; return x; } int main() { scanf("%s",s); fail[0]=1;len[1]=-1; for(int i=0,poz;s[i];i++) { if(i!=0) s[i]=(s[i]-97+ls)%26+97; poz=get(i,now); if(!tr[poz][s[i]-'a']) { fail[++tot]=tr[get(i,fail[poz])][s[i]-'a']; tr[poz][s[i]-'a']=tot; len[tot]=len[poz]+2; num[tot]=num[fail[tot]]+1; } now=tr[poz][s[i]-'a']; cout<<(ls=num[now])<<" "; } }
然後$T3$就和切菜一樣了
#include<bits/stdc++.h> #define MAXN 1100000 using namespace std; char s[MAXN]; int fail[MAXN],len[MAXN],num[MAXN],tr[MAXN][30],Ed[MAXN],ls=0,now=0,tot=1; int head[MAXN],nxt[MAXN],to[MAXN],fa[MAXN][26],siz,l1,r1,l2,r2,n,q,dep[MAXN]; bool flag; void add(int u,int v) { siz++; to[siz]=v; nxt[siz]=head[u]; head[u]=siz; } int get(int i,int x) { while(i-len[x]-1<0||s[i-len[x]-1]!=s[i]) x=fail[x]; return x; } void dfs(int now,int f) { fa[now][0]=f; dep[now] = dep[f] + 1; for(int i=head[now];i;i=nxt[i]) { int y=to[i]; if(y==f) continue; dfs(y,now); } } int lca(int x, int y) { if(dep[x] < dep[y]) swap(x, y); for(int i = 20; i >= 0; --i) if(dep[fa[x][i]] >= dep[y]) x = fa[x][i]; if(x ==y) return x; for(int i = 20; i >= 0; --i) { if(fa[x][i] != fa[y][i]) {x = fa[x][i], y = fa[y][i]; } } if(fa[x][0]==-1) flag=1; return fa[x][0]; } int main() { scanf("%d%d",&n,&q); scanf("%s",s); fail[0]=1;len[1]=-1; add(1,0); for(int i=0;i<n;i++) { s[i+n]=s[n-i-1]; } for(int i=0,poz;s[i];i++) { poz=get(i,now); if(!tr[poz][s[i]-'a']) { fail[++tot]=tr[get(i,fail[poz])][s[i]-'a']; tr[poz][s[i]-'a']=tot; add(fail[tot],tot); len[tot]=len[poz]+2; // num[tot]=num[fail[tot]]+1; } now=tr[poz][s[i]-'a']; Ed[i]=now; } memset(fa,-1,sizeof(fa)); dfs(1, -1); for(int i=1;i<=20;i++) { for(int j=0;j<=tot;j++) { fa[j][i]=fa[fa[j][i-1]][i-1]; } } for(int i=1,ed1,ed2,Len;i<=q;i++) { scanf("%d%d%d%d",&l1,&r1,&l2,&r2); Len=min(r1-l1+1,r2-l2+1); r1=2*n-r1+1; l1=2*n-l1+1; swap(l1,r1); r1--, r2--; ed1=Ed[r1]; ed2=Ed[r2]; flag=0; ed1 = lca(ed1, ed2); if(flag==1) { cout<<0; continue; } if(len[ed1]<=Len) { cout<<-len[ed1]<<endl; continue; } for(int j=20;j>=0;j--) { // cout<<"ed1: "<<fa[ed1][j]<<endl; if(len[fa[ed1][j]]>Len) { ed1=fa[ed1][j]; } } cout<<-len[fa[ed1][0]]<<endl; } }