1. 程式人生 > >【2018.11.3】阿伏伽德羅 / 聯絡 / 歐幾里得距離

【2018.11.3】阿伏伽德羅 / 聯絡 / 歐幾里得距離

int main(){

  while(模擬賽) 降智++;

    return inf;

}

題目

T1

剛看到題時還以為不可做,重新看了幾遍之後才發現以前好像做過……

做法很顯然吧……

由於第一行存在 $1-n$ 的數各一個,我們可以先把列 按照第一行的數從大到小排序,這樣第 $i$ 列第 $1$ 行的數就是 $i$ 了,方便後續操作。

容易發現,如果第 $2$ 或 第 $3$ 行不存在某個數,那第一行的這個數肯定匹配不上 $2$、$3$ 行相同的數,把這個數在第一行所在的那一列刪掉。

然後刪掉一列之後,第 $2$、$3$ 行就各少了一個數,那第 $2$ 或 第 $3$ 行就有可能又出現一個不存在的數。重複上述刪除過程即可。

可以把要刪除的列的編號扔進一個佇列,挨個取出後操作。時間複雜度是列數級別,即 $O(n)$。


 

T2

講道理,這題的做法以前講過……

$dp(i,s)$ 表示考慮到第 $i$ 條邊,點的劃分集合為 $s$ 時,


 

T3

超綱題

由於資料較水,$O(n^2*log(n))$ 的隨機更新 $Dij$ 就卡 $A$ 了……

 1 #include<bits/stdc++.h>
 2 #define rep(i,x,y) for(register int i=(x);i<=(y);i++)
 3 #define
dwn(i,x,y) for(register int i=(x);i>=(y);i--) 4 #define maxn 1510 5 #define maxnum (maxn*maxn) 6 #define maxm 300010 7 using namespace std; 8 int read() 9 { 10 int x=0,f=1;char ch=getchar(); 11 while(!isdigit(ch)&&ch!='-')ch=getchar(); 12 if(ch=='-')f=-1,ch=getchar();
13 while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); 14 return x*f; 15 } 16 void write(int x) 17 { 18 int f=0;char ch[20]; 19 if(!x){putchar('0'),putchar('\n');return;} 20 if(x<0)x=-x,putchar('-'); 21 while(x)ch[++f]=x%10+'0',x/=10; 22 while(f)putchar(ch[f--]); 23 putchar('\n'); 24 } 25 char s[maxn][maxn]; 26 int qx[maxnum],qy[maxnum],dis[maxn][maxn],vis[maxn][maxn],fx[maxn][maxn],fy[maxn][maxn],n,m,num; 27 typedef struct node{int x,y,w;bool operator <(const node &z)const{return w>z.w;}}stnd; 28 priority_queue<stnd>q; 29 stnd make(int x,int y,int w){stnd tmp;tmp.x=x,tmp.y=y,tmp.w=w;return tmp;} 30 int dx[8]={0,1,1,1,0,-1,-1,-1},dy[8]={1,0,-1,1,-1,0,-1,1}; 31 int d(int xa,int ya,int xb,int yb){return (xa-xb)*(xa-xb)+(ya-yb)*(ya-yb);} 32 int yes(int x,int y){if(x>=1&&x<=n&&y>=1&&y<=n)return 1;return 0;} 33 int main() 34 { 35 freopen("dist.in","r",stdin); 36 freopen("dist.out","w",stdout); 37 srand(time(0)); 38 n=read(); 39 memset(dis,0x7f,sizeof(dis)); 40 rep(i,1,n) 41 { 42 scanf("%s",s[i]+1); 43 rep(j,1,n) 44 if(s[i][j]=='1') 45 { 46 fx[i][j]=i,fy[i][j]=j,dis[i][j]=0; 47 q.push(make(i,j,0)); 48 } 49 rep(j,1,n)if(s[i][j]=='1')qx[++num]=i,qy[num]=j; 50 } 51 m=read(); 52 if(n<=300&&(m<=300||num*m<=100000000)) 53 { 54 while(m--) 55 { 56 int x=read(),y=read(),ans=2147483647; 57 rep(i,1,num)if(d(x,y,qx[i],qy[i])<ans)ans=d(x,y,qx[i],qy[i]); 58 write(ans); 59 } 60 return 0; 61 } 62 while(!q.empty()) 63 { 64 int ux=q.top().x,uy=q.top().y; 65 if(q.top().w>dis[ux][uy]){q.pop();continue;} 66 q.pop(); 67 rep(i,0,7) 68 { 69 int nx=ux+dx[i],ny=uy+dy[i]; 70 if(!yes(nx,ny))continue; 71 if(dis[nx][ny]==d(fx[ux][uy],fy[ux][uy],nx,ny)&&(fx[ux][uy]!=fx[nx][ny]||fy[ux][uy]!=fy[nx][ny])) 72 { 73 if(rand()&1)fx[nx][ny]=fx[ux][uy],fy[nx][ny]=fy[ux][uy]; 74 } 75 if(dis[nx][ny]>d(fx[ux][uy],fy[ux][uy],nx,ny)) 76 { 77 dis[nx][ny]=d(fx[ux][uy],fy[ux][uy],nx,ny); 78 fx[nx][ny]=fx[ux][uy],fy[nx][ny]=fy[ux][uy]; 79 // cout<<"nx:"<<nx<<" ny:"<<ny<<" dis:"<<dis[nx][ny]<<endl; 80 q.push(make(nx,ny,dis[nx][ny])); 81 } 82 } 83 } 84 while(m--) 85 { 86 int x=read(),y=read(); 87 write(dis[x][y]); 88 } 89 return 0; 90 }
SYF

當然更暴力的就直接 $KDTree$ 了(好短啊)……

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
inline int read()
{
    int x = 0,f = 1;char ch = getchar();
    for(;!isdigit(ch);ch = getchar())if(ch == '-')f = -f;
    for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
    return x * f;
}
const int MX = 1500 * 1500 + 10;
const LL inf = 1e18;
 
struct Point
{
    int xy[2], l, r, id;
} P[MX];
int cmpw; LL ans;
char grid[1510][1510],inh[1510][1510];
bool cmp(const Point &a, const Point &b) {return a.xy[cmpw] < b.xy[cmpw];}
int build(int l, int r, int w)
{
    int m = (l + r) >> 1; cmpw = w;
    nth_element(P + l, P + m, P + 1 + r, cmp);
    P[m].l = l != m ? build(l, m - 1, !w) : 0;
    P[m].r = r != m ? build(m + 1, r, !w) : 0;
    return m;
}
LL dist(LL x, LL y = 0) {return x * x + y * y;}
void query(int rt, int w, LL x, LL y)
{
    LL temp = dist(x - P[rt].xy[0], y - P[rt].xy[1]);
    if(temp) ans = min(ans, temp);
    if(P[rt].l && P[rt].r)
    {
        bool sign = !w ? (x <= P[rt].xy[0]) : (y <= P[rt].xy[1]);
        LL d = !w ? dist(x - P[rt].xy[0]) : dist(y - P[rt].xy[1]);
        query(sign ? P[rt].l : P[rt].r, !w, x, y);
        if(d < ans) query(sign ? P[rt].r : P[rt].l, !w, x, y);
    }
    else if(P[rt].l) query(P[rt].l, !w, x, y);
    else if(P[rt].r) query(P[rt].r, !w, x, y);
}
 
int main()
{
    freopen("dist.in","r",stdin);
    freopen("dist.out","w",stdout);
    int n,nm = 0;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        scanf("%s",grid[i] + 1);
        for(int j = 1; j <= n; j++)
        {
            if(grid[i][j] == '1')
            {
                nm++; 
                P[nm].xy[0] = i;
                P[nm].xy[1] = j;
                inh[i][j] = 1;
            }
        }
    }
    int rt = build(1, nm, 0);
    int q;scanf("%d",&q);
    while(q--)
    {
        int x = read(),y = read();
        if(inh[x][y]){puts("0");continue;}
        ans = inf;
        query(rt, 0, x, y);
        printf("%lld\n", ans);
    }
}
HX

老師的做法……其實是斜率優化 $dp$。

就是說,可以先預處理出每個數在自己那一行上到離他最近的豆子的距離,然後再推出每個數在豎列上的最優取值:

$dis_{i,j}=\min\{dis_{i',j}^2+(i-i')^2\} \space | \space i'\le i$

(當然,從下往上還得推一次)

上式轉化得到 $dis_{i,j}=\min\{dis_{i',j}^2 - 2\times i\times i' + i'^2\}+i^2 \space | \space i'\le i$