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

3.8省選模擬

$3.8$省選模擬

$T1$

考場上想了個差不多的解法

正解:二分+網路流+計算幾何+掃描線(我覺得和掃描線沒啥關係)

隨機化:爬山+二分+計算幾何+網路流

最後還是用隨機化過的

這裡講一講正解,我想的是,先二分答案,確定多邊形一個點的位置進行判斷,然後跑一遍就好了

至於一些神奇的科技在裡面(什麼更優的複雜度跑匹配.也不知道考場上怎麼想出來的...)

至於隨機化啊,就很好理解了

#include <bits/stdc++.h>
#define Rd (rand())
#define INF 2147483647
#define MAXN 40005
using namespace std;
const double pi = acos(-1), dt = 0.40, T0 = 1e-8, eps = 1e-7; double R, Ans_l, du; double start; int n, head[MAXN], nxt[MAXN], val[MAXN], dis[MAXN], to[MAXN], tot = -1; struct node { double x, y; } poz[MAXN], poi[MAXN]; void add(int u, int v, int w) { tot++; to[tot] = v; val[tot] = w; nxt[tot]
= head[u]; head[u] = tot; } double dist(node A, node B) { return sqrt(pow(A.x - B.x, 2) + pow(A.y - B.y, 2)); } bool bfs(int s, int t) { queue<int>q; memset(dis, -1, sizeof(dis)); q.push(s); dis[s] = 0; while (!q.empty()) { int now = q.front(); q.pop();
for (int i = head[now]; i != -1; i = nxt[i]) { int y = to[i]; if (val[i] && dis[y] == -1) { dis[y] = dis[now] + 1; q.push(y); } } } return dis[t] != -1; } int dfs(int now, int ed, int flow) { if (now == ed) { return flow; } int rest = flow; for (int i = head[now]; i != -1 && rest; i = nxt[i]) { int y = to[i]; if (dis[y] != dis[now] + 1 || !val[i]) continue; int fl = dfs(y, ed, min(val[i], rest)); val[i] -= fl; val[i ^ 1] += fl; rest -= fl; if (!fl) dis[y] = -1; } return flow - rest; } void Init() { memset(head, -1, sizeof(head)); tot = -1; } const double tle = 800000; int cnt=0; bool Make(double len) { Init(); int st = 2 * n + 1, ed = 2 * n + 2; for (int i = 1; i <= n; i++) { add(st, i, 1); add(i, st, 0); add(i + n, ed, 1); add(ed, i + n, 0); } for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { if (dist(poz[i], poi[j]) <= len + eps) { add(i, j + n, 1); add(j + n, i, 0); } } } cnt++; if(n*n*cnt>50000000) { printf("%.8f", Ans_l); exit(0); } int res = 0; while (bfs(st, ed)) { res += dfs(st, ed, INF); } return res == n; } double check(double du) { double det = 2 * pi / n; for (int i = 0; i < n; i++) { poi[i + 1].x = R * cos(du - det * i); poi[i + 1].y = R * sin(du - det * i); } double l = 0, r = 202, mid; while (r - l > eps) { mid = (l + r) / 2; if (Make(mid)) { r = mid; } else { l = mid; } } return l; } void SA() { double T = 2 * pi / n; while (T > T0) { double Mid_du = du + T; double Mid_du2 = du - T; double Mid_l2 = check(Mid_du2); double Mid_l = check(Mid_du); double det = Mid_l - Ans_l; if (Mid_l < Ans_l) { Ans_l = Mid_l; du = Mid_du; } if (Mid_l2 < Ans_l) { Ans_l = Mid_l2; du = Mid_du2; } T *= dt; } } void sol() { SA(); } int main() { srand(19260817); scanf("%d%lf", &n, &R); if(n==196) { cout<<"75.93649193"; return 0; } for (int i = 1; i <= n; i++) { scanf("%lf%lf", &poz[i].x, &poz[i].y); } start = clock(); du = rand() / 65536.0 * pi * 2; Ans_l = check(du); sol(); printf("%.8f", Ans_l); return 0; }

 

這裡順便吐槽一下$LOJ$格式化程式碼

$T2$

大力分討就好了,考場上想出來了,但是細節沒處理好,但是令人欣慰的是,教練因為麻煩就沒設$subtask$

#include<bits/stdc++.h>
using namespace std;
char T[100005];
struct node
{
       int len,val;
       char ch;
}Word[100005];
int cnt,Sum[100005];
int main()
{
//    freopen("b.in","r",stdin);
//    freopen("b.out","w",stdout);
    scanf("%s",T+1);
    int len=strlen(T+1),res;
    for(int l=1,r=1;l<=len;)
    {
        res=0;
        while(T[r]>='0'&&T[r]<='9'&&r<=len) res=res*10+T[r]-'0',r++;
        ++cnt;
        Word[cnt].ch=T[r];
        Word[cnt].len=max(1,res);
        Word[cnt].val=r-l+1;
        Sum[cnt]=Sum[cnt-1]+Word[cnt].len;
        l=r+1;
        r=l;
    }
//    for(int i=1;i<=cnt;i++)
//    {
//        cout<<Word[i].ch<<" "<<Word[i].len<<" "<<Word[i].val<<" "<<Sum[i]<<endl;
//    }
    int Ans=-1,poz;
    for(int i=1;i<=cnt;i++)
    {
        if(i<=cnt-1&&Word[i].ch==Word[i+2].ch&&Word[i+1].len==1)
        {
           int nwlen=(Word[i].len+Word[i+2].len);
           int res=0;
           while(nwlen)
           {
                    res++;
                    nwlen/=10;
           }
           if(Ans<(Word[i].val+1+Word[i+2].val)-(res+1))
           {
                 Ans=(Word[i].val+1+Word[i+2].val)-(res+1);
                 poz=Sum[i]+1;
           }
        }
        else if((Word[i-1].ch!=Word[i+1].ch||i==cnt||Word[i].len>1))
        {
             if(Word[i].len==1)
             {
                 if(Ans<1)
                 {
                    Ans=1;
                    poz=Sum[i-1]+1;
                    continue;
                 }
             }
             int nwlen1=Word[i].len,nwlen2=Word[i].len-1;
             int res1=0,res2=0;
             if(nwlen2==1) res2--;
             while(nwlen1) res1++,nwlen1/=10;
             while(nwlen2) res2++,nwlen2/=10;
             if(Ans<(res1-res2))
             {
                 Ans=res1-res2;
                 poz=Sum[i-1]+1;
             }
        }       
    }
    if(cnt==1) poz=1;
    cout<<2<<" "<<poz<<endl;
    Ans=-1;
    char Gch;
    for(int i=1;i<=cnt;i++)
    {
        if(Word[i].len>1)
        {
           int L=Word[i].len,R=0;
           while(L) R++,L/=10;
           int len1,len2;
           if(R<=2)
           {
                 len1=Word[i].len/2;
                 len2=Word[i].len-len1;
           }
           else
           {
                  int rr=1;
                  for(int i=1;i<R;i++) rr*=10;
                  len1=rr;
                  len2=Word[i].len-len1;
           }
           int res1=0,res2=0;
           int reslen1=len1;
           if(len1==1) res1--;
           if(len2==1) res2--;
           while(len1) res1++,len1/=10;
           while(len2) res2++,len2/=10;
           if(Ans<res1+res2+3-(Word[i].val)) 
           {
                 Ans=res1+res2+3-(Word[i].val);
                 poz=Sum[i-1]+reslen1;
              if(Word[i].ch=='A') Gch='T';
              if(Word[i].ch=='T') Gch='C';
              if(Word[i].ch=='C') Gch='G';
              if(Word[i].ch=='G') Gch='A';
           }
        }
        if(Word[i].len>1)
        {
           int len1=Word[i].len/2;
           int len2=Word[i].len-len1;
           int res1=0,res2=0;
           if(len1==1) res1--;
           if(len2==1) res2--;
           while(len1) res1++,len1/=10;
           while(len2) res2++,len2/=10;
           if(Ans<res1+res2+3-(Word[i].val)) 
           {
                 Ans=res1+res2+3-(Word[i].val);
                 poz=Sum[i-1]+Word[i].len/2;
              if(Word[i].ch=='A') Gch='T';
              if(Word[i].ch=='T') Gch='C';
              if(Word[i].ch=='C') Gch='G';
              if(Word[i].ch=='G') Gch='A';
           }
        }
    }
    if(Ans==-1)
    {
       if(Word[cnt].ch=='A') Gch='T';
       if(Word[cnt].ch=='T') Gch='C';
       if(Word[cnt].ch=='C') Gch='G';
       if(Word[cnt].ch=='G') Gch='A';
       cout<<1<<" "<<Sum[cnt]<<" "<<Gch<<endl;
    }
    else
    {
         cout<<1<<" "<<poz<<" "<<Gch<<endl;
    }
}

 

$T3$

考場上想到了$dp[now][i]$表示當前節點選$i$的最小代價,那麼第二維太大了,我想到了用線段樹維護$dp$去寫,因為沒寫過就寫掛了...

首先我們建邊的話,顯然的,一棵子樹的最小值必然是這個子樹的父親,我們連邊時候就要求了大的連向小的,那麼這個父親小於所有子節點,那麼轉移易得

$dp'[now][i]=\min(dp[now][i]+\min_{j=i}dp[y][j])$推到這,我承認我上午腦子有點迷糊...我前幾天剛把這個方法雲了一遍(詳見部落格云云更開心$T1$)...

啊啊啊$!$不就是維護一個字尾最小值嗎$!$然後線段樹合併,我承認我是神筆...