1. 程式人生 > 其它 >3.18省選模擬

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;
    }
}