【URAL 刷題記】URAL 1317 ~ URAL 1326

URAL 1317

/*
A題題意:一個用高度爲h的圍欄圍住的停車場裏面有一個激光發射器,它可以消滅距離在R之內的冰雹(冰雹不能落到比圍欄低的位置或者被圍欄擋住),求可以消滅的冰雹的數量
解法:先確定冰雹與凸包的位置關係,然後分類討論(1)冰雹落點在凸包裏面,直接計算最小距離是否大於R(2)冰雹落點在凸包外面,當冰雹恰好未被圍欄擋住時距離最小,求出冰雹與發射器連線與圍欄在平面上的交點,再利用相似三角形求出最小距離與R比較

注意線段與線段求交。。。 
*/
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;

const double PI = acos(-1.0);
const double eps = 1e-10;
const double INF = 1e5;

int dcmp(double x) { if (fabs(x) < eps) return 0; else return x < 0 ? -1 : 1; }

// Point Vector
struct Point {
    double x, y;
    Point() { }
    Point(double x, double y) : x(x), y(y) { }
    bool operator < (const Point &A) const {
        return dcmp(x-A.x) < 0 || (dcmp(x-A.x) == 0 && dcmp(y-A.y) < 0);
    }
    void read(){
        double x,y; scanf("%lf%lf",&x,&y);
        this->x=x, this->y=y;
    }
};
typedef Point Angle;
typedef Point Vector;
Point operator + (const Point &A, const Point &B)   { return Point(A.x+B.x, A.y+B.y); }
Point operator - (const Point &A, const Point &B)   { return Point(A.x-B.x, A.y-B.y); }
Point operator * (const Point &A, double b)         { return Point(A.x*b, A.y*b); }
Point operator / (const Point &A, double b)         { return Point(A.x/b, A.y/b); }
bool operator == (const Point &A, const Point &B)   { return dcmp(A.x-B.x) == 0 && dcmp(A.y-B.y) == 0; }
double Dot(const Point &A, const Point &B)          { return A.x*B.x + A.y*B.y; }
double Cross(const Point &A, const Point &B)        { return A.x*B.y - A.y*B.x; }

double Length(const Point &A) { return sqrt(Dot(A, A)); }
double Area2(const Point &A, const Point &B, const Point &C) { return Cross(B-A, C-A); }
Point Rotate(const Point &A, double ang) {
    return Point(cos(ang)*A.x - sin(ang)*A.y, sin(ang)*A.x + cos(ang)*A.y);
}
Point Normal(const Point &A) {
    double L = Length(A); return Point(-A.y/L, A.x/L);
}

// Line Segment
struct Line {
    Point A, B, v;
    double ang;

    Line() { }
    Line(Point A, Point B): A(A), B(B) { v = B-A; ang = atan2(v.y, v.x); }
    // ax + by + c > 0
    Line(double a, double b, double c) {
        v = Point(b, -a);
        if (fabs(a) > fabs(b)) A = Point(-c/a, 0); else A = Point(0, -c/b);
        B = A + v;
        ang = atan2(v.y, v.x);
    }
    bool operator < (const Line &A) const { return ang < A.ang; }
    Point point(double t) const { return A + v*t; }
};

int LineLineIntersection(const Line& L1, const Line& L2, Point* p, double* t=0) {
    if(dcmp(Cross(L1.v,L2.v))==0)
        return dcmp(Cross(L1.v,L2.A-L1.A))==0 ? -1 : 1;
    p[0]=L1.point(Cross(L2.v, L1.A-L2.A) / Cross(L1.v, L2.v));
    if(t) t[0]=Cross(L2.v, L1.A-L2.A) / Cross(L1.v, L2.v);
    return 1;
}

double DistanceToLine(const Point &P, const Line &L) {
    return fabs(Cross(L.v, P-L.A)) / Length(L.v);
}
Point GetLineProjection(const Point &P, const Line &L) {
    return L.point(Dot(P-L.A, L.v) / Dot(L.v, L.v));
}
int Position(const Point &P, const Line &L) { return dcmp(Cross(L.v, P-L.A)); }

double DistanceToSegment(const Point &P, const Line &L) {
    if (dcmp(Dot(L.v, P-L.A)) < 0) return Length(P-L.A);
    else if (dcmp(Dot(L.v, P-L.B) > 0)) return Length(P-L.B);
    else return DistanceToLine(P, L);
}
bool SegmentProperIntersection(const Line &L1, const Line &L2) {
    int c1 = Position(L2.A, L1), c2 = Position(L2.B, L1),
        c3 = Position(L1.A, L2), c4 = Position(L1.B, L2);
    return c1*c2 < 0 && c3*c4 < 0;
}
bool OnSegment(const Point &P, const Line &L) {
    return  dcmp(Cross(L.A-P, L.B-P)) == 0 &&
            dcmp(Dot(L.A-P, L.B-P)) <= 0;
}
bool OnSegment2(const Point &P, const Line &L) {
    return dcmp(L.A.x - P.x) * dcmp(L.B.x - P.x) <= 0 && dcmp(L.A.y - P.y) * dcmp(L.B.y - P.y) <= 0;
}

// Polygon
typedef vector<Point> Polygon;
typedef std::vector<Line> Lines;
void print(const Polygon& A) {
    for (int i = 0; i < A.size(); ++ i) printf("%.2lf %.2lf\n", A[i].x, A[i].y);
}

double PolygonArea(const Polygon &p) {
    int n = p.size();
    double area = 0;
    for (int i = 1; i < n-1; ++ i)
        area += Area2(p[0], p[i], p[i+1]);
    return area / 2.0;
}
int isPointInPolygon(const Point &P, const Polygon &p) {
    int n = p.size();
    int wn = 0;
    for (int i = 0; i < n; ++ i) {
        const Point &p1 = p[i]; const Point &p2 = p[(i+1)%n];
        if (P == p1 || P == p2 || OnSegment(P, Line(p1, p2))) return -1;
        int k = dcmp(Cross(p2-p1, P-p1));
        int d1 = dcmp(p1.y-P.y);
        int d2 = dcmp(p2.y-P.y);
        if (k > 0 && d1 <= 0 && d2 > 0) ++ wn;
        if (k < 0 && d2 <= 0 && d1 > 0) -- wn;
    }
    return wn != 0;
}
// ConvexHull
Polygon ConvexHull(Polygon p) {
    int n = p.size();
    sort(p.begin(), p.end());

//  int n = p.erase(std::unique(p.begin(), p.end()), p.end());
    Polygon q(n+1);
    int m = 0;
    for (int i = 0; i < n; ++ i) {
        while (m > 1 && Cross(q[m-1]-q[m-2], p[i]-q[m-2]) <= 0) -- m;
        q[m ++] = p[i];
    }
    int k = m;
    for (int i = n-2; i >= 0; -- i) {
        while (m > k && Cross(q[m-1]-q[m-2], p[i]-q[m-2]) <= 0) -- m;
        q[m ++] = p[i];
    }
    if (n > 1) m --;
    q.resize(m);
    return q;
}

int n,m;
Polygon A;

double H, D;
Point las, stone;

double sqr(double x){return x*x;}

void solve(){
    scanf("%d",&n); A.resize(n);
    scanf("%lf",&H);
    for(int i=0;i<n;++i) A[i].read();

    scanf("%lf",&D); las.read();
    scanf("%d",&m);
    int res=0;
    while(m--){
        stone.read();
        if(isPointInPolygon(stone,A)){
            ++res;
        }else{
            Line L=Line(las,stone);
            Point p; double t;
            for(int i=0;i<n;++i){
                Line Lx=Line(A[i],A[(i+1)%n]);
                if(LineLineIntersection(L,Lx,&p,&t)==1&&OnSegment(p,Lx)&&dcmp(t)>=0)break;
            }

            double d=Length(L.v)/Length(p-las)*sqrt(sqr(Length(p-las))+sqr(H));
            if(dcmp(d-D)<=0) ++ res;
        }
    }
    printf("%d\n",res);
}
int main(){
//  freopen("in.txt","r",stdin);
    solve();
//  for(;;);
    return 0;
}

URAL 1318

/*
題意:看公式。。。
題解: 
10^0~10^38打個表出來
然後二分每個數在哪兩個之間

坑點:注意不要越界qwq,打到39的時候,答案還比38大=-=,天真的以爲沒越界。。。 
*/
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;

typedef long long LL;

const int MAXLOG=39;
struct bign{
    unsigned a[4];
    bign(){ memset(a,0,sizeof a); }
    bool operator<(const bign& B)const{
        for(int i=3;i>=0;--i)if(a[i]!=B.a[i]) return a[i]<B.a[i];
        return 0;
    }
} num[MAXLOG];

bign operator*(const bign& A,int b){
    bign C;
    LL p=0;
    for(int i=0;i<4;++i){
        p = (p >> 32) + ((LL)A.a[i]*b);
        C.a[i] = (p&(0xffffffff));
    }
    return C;
}
bign operator^(const bign& A,const bign& B){
    bign C;
    for(int i=0;i<4;++i){
        C.a[i]=A.a[i]^B.a[i];
    }
    return C;
}

const int maxn=5010;

bign A[maxn];
int n;
void solve(){
    scanf("%d",&n);
    for(int i=0;i<n;++i) for(int j=3;j>=0;--j) scanf("%u",&A[i].a[j]);

    int res=0;
    for(int i=0;i<n;++i)
        for(int j=0;j<n;++j){
            int x=upper_bound(num,num+MAXLOG,A[i]^A[j])-num-1;
            res += max(x,0);
        }
    printf("%d\n",res);
}
int main(){
//  freopen("in.txt","r",stdin);
    num[0].a[0]=1;
    for(int i=1;i<MAXLOG;++i)
        num[i]=num[i-1]*10;

    solve();
//  for(;;);
    return 0;
}

URAL 1319

/*
C題題意是在n*n的矩陣裏填數,從右上角開始填。每次向右下角填。
模擬
*/

#include<algorithm>
#include<cstdio>
#include<cstring>

const int maxn=110;

int a[maxn][maxn];

int n;

void solve(){
    scanf("%d",&n);

    int no=0;
    {
        int i=1;
        for(int j=n;j>=1;--j)
            for(int k=0;j+k<=n;++k)
                a[i+k][j+k]=++no;
    }
    {
        int j=1;
        for(int i=2;i<=n;++i)
            for(int k=0;i+k<=n;++k)
                a[i+k][j+k]=++no;
    }

    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
            printf("%d%c", a[i][j], j==n?'\n':' ');
}
int main(){
//  freopen("in.txt","r",stdin);
    solve();
//  for(;;);
    return 0;
}

URAL 1320

/*
題意:給一張圖,問是否可以用若干個“相鄰邊對”來劃分整個圖。。“相鄰邊對”定義爲兩條邊有公共點。。
題解:每個聯通塊邊數爲偶數,答案爲T,否則False
(怎麼證。。。) 
*/ 
#include<algorithm>
#include<cstdio>
#include<cstring>

const int maxn=1010;

int pa[maxn];
int findset(int x){ return pa[x]==x ? x : pa[x]=findset(pa[x]); }

int sz[maxn];
int deg[maxn];

void solve(){
    for(int i=1;i<maxn;++i)pa[i]=i;

    int u,v;
    while(scanf("%d%d",&u,&v)==2){
        ++deg[u],++deg[v];
        int p=findset(u),q=findset(v);
        if(p!=q) pa[p]=q, sz[q]=sz[q]+sz[p]+1;
        else sz[p]++;
    }

    int fg=1;
    for(int i=1;i<=1000;++i){
        int p=findset(i);
        if(sz[p]&1){ fg=0; break; }
    }
    puts(fg ? "1" : "0");
}
int main(){
//  freopen("in.txt","r",stdin);
    solve();
//  for(;;);
    return 0;
}

URAL 1321

/*
題意:電梯顯示屏有故障,顯示數字每一位有7個顯像管,然後問最少坐幾層樓能排查出所有故障的顯像管。(故障可能是始終亮或始終暗) 
例如,10層樓,至少需要2-10共8層樓,才能排除所有故障。
注意:顯示不含前導0,並且用不到的顯像管不需要排查。 
題目保證層數>4 
題解:
分類討論:
如果只有一位,因爲題目保證層數>4,所以每根顯像管都用上了,所以一定要是[1,5]共4層。 
如果第一位是[4,9],那麼第一位所有顯像管都必須排查,故一定是[19999...,40000...]共30000...01層
如果第一位是[2,3],那麼除了左上角那一位其餘所有都必須排查,故一定是[09999...,20000...]共10000...01層
如果第一位是1,那麼注意:此時的第二位始終會顯示0,而10個數字中,右下角的顯像管必須有2才能排查,故
如果第二位是[2,9],那麼就是[069999...,120000...],共050000...01層
如果第二位是[0,1],那麼就是[029999...,10000...],共070000...01層
*/
#include<algorithm>
#include<cstdio>
#include<cstring>

const int maxn=1010;

char num[maxn];
int n;
void solve(){
    scanf("%s",num); n=strlen(num);
    if(n==1){
        puts("4"); return;
    }
    if(num[0]>='4'){
        for(int i=0;i<n;++i){
            if(i==0)putchar('3');
            else if(i==n-1)putchar('1');
            else putchar('0');
        }
        return;
    }
    if(num[0]>='2'){
        for(int i=0;i<n;++i){
            if(i==0)putchar('1');
            else if(i==n-1)putchar('1');
            else putchar('0');
        }
        return;
    }

    //num[0]=='1'
    if(num[1]>='2'){
        if(n==2){ putchar('6'); return; }
        for(int i=1;i<n;++i){
            if(i==1)putchar('5');
            else if(i==n-1)putchar('1');
            else putchar('0');
        }
        return;
    }
    //num[1]>='0'
    {
        if(n==2){ putchar('8'); return; }
        for(int i=1;i<n;++i){
            if(i==1)putchar('7');
            else if(i==n-1)putchar('1');
            else putchar('0');
        }
        return;
    }
}

int main(){
//  freopen("in.txt","r",stdin);
    solve();
//  for(;;);
    return 0;
}

URAL 1322

/*
題意:一個字符串的所有循環同構按照字典序排序。按順序給出每種同構的最後一位,求第k小的同構。n <= 10^5
題解:
他給出的那個串一定包括了這個串的所有字母。那麼第一位一定是按照大小把他們擺放好。然後就確定了每個字母后面是哪個字母,然後一直找下去就能把這個串構造出來
把他們按照給出的順序編號,那麼我們可以確定每號字母后面的字母是第幾號。那麼從第k號開始連續找n個就行 
*/ 
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#include<functional>
using namespace std;


const int maxsigma=53;
int idx(char x){ return 'A'<=x&&x<='Z' ? x-'A' : (x=='_' ? x-'_'+26 : x-'a'+27); }

const int maxn=100010;

int m;
char s[maxn],t[maxn]; int n;
vector<int> nxt[maxsigma];
int no[maxsigma+10];
int go[maxn];

void solve(){
    scanf("%d",&m);
    scanf("%s",s);n=strlen(s);
    memcpy(t,s,sizeof s); sort(t,t+n);
    memset(no,0,sizeof no);
    for(int i=0;i<n;++i)
        ++no[idx(s[i])+1];
    for(int i=1;i<=maxsigma;++i) no[i]+=no[i-1];
    for(int i=0;i<n;++i)
        go[no[idx(s[i])]++]=i;
    int p=m-1;
    for(int i=0;i<n;++i){
        putchar(t[p]);
        p=go[p];
    }
    putchar('\n');
}
int main(){
//  freopen("in.txt","r",stdin);
    solve();
//  for(;;);
    return 0;
}

URAL 1323

#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#include<vector>
using namespace std;

const int INF=0x3f3f3f3f;

typedef pair<int,int> P;
const int maxn=11;

int f[1<<maxn][1<<maxn]; P g[1<<maxn][1<<maxn]; 
int upd(int& a,int b){ return a>b ? a=b,1 : 0; }

int n,m;

P Q[500000]; int l,r;
int G[maxn][maxn];
char s1[30],s2[30];

int lg2[1<<maxn];

map<string, int> idx;
string iidx[maxn];
int idxN;
int index(string s){
    if(!idx.count(s)){ idx[s]=idxN; iidx[idxN]=s; ++ idxN; return idxN-1; }
    return idx[s];
}

vector<P> ans[maxn];
void print(int x,int y,int lx,int ly){
    if(g[x][y].first) print(g[x][y].first,g[x][y].second,x,y);
    if(f[lx][ly]>f[x][y]) return;
    if(lx!=-1){
        ans[f[x][y]].push_back(P(lg2[y^ly],lg2[x^lx]));
//      printf("%s %s\n",iidx[lg2[y^ly]].c_str(),iidx[lg2[x^lx]].c_str());
    }
}
void solve(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;++i){
        scanf("%s%s",s1,s2);
        int n1=index(s1),n2=index(s2);
        G[n1][n2]=G[n2][n1]=1;
    }
    memset(f,0x3f,sizeof f);
    scanf("%s",s1);
    int s=index(s1);
    f[1<<s][0]=0;
    l=r=0; Q[r++]=P(1<<s,0);
    for(;l!=r;++l){
        int x=Q[l].first,y=Q[l].second;
        int d=f[x][y];
        for(int i=0;i<n;++i)if((y>>i)&1){
            for(int j=0;j<n;++j)if(G[i][j]&&!((x>>j)&1)){
                if(upd(f[x|(1<<j)][y&~(1<<i)],d)){ // 選一個這一輪的人,再選一個點拓展 
                    Q[r++]=P(x|(1<<j),y&~(1<<i));
                    g[x|(1<<j)][y&~(1<<i)]=Q[l];
                } 
            }
        }
        if(upd(f[x][x],d+1)){ // 更新一輪 
            Q[r++]=P(x,x);
            g[x][x]=Q[l];
        }
    }
    int mnf=INF; P mni;
    for(int i=0;i<(1<<n);++i)if(upd(mnf,f[(1<<n)-1][i]))
        mni=P((1<<n)-1,i);
    printf("%d\n",mnf);
    print(mni.first,mni.second,-1,-1);
    for(int i=1;i<=mnf;++i){
        printf("%d\n",ans[i].size());
        for(int j=0;j<ans[i].size();++j)printf("%s %s\n",iidx[ans[i][j].first].c_str(),iidx[ans[i][j].second].c_str());
    }
}
int main(){
//  freopen("in.txt","r",stdin);
    lg2[0]=-1; for(int i=1;i<(1<<maxn);++i)lg2[i]=lg2[i-1]+!(i&(i-1));
    solve();
//  for(;;);
    return 0;
}

URAL 1324

URAL 1325

URAL 1326

/*
J題題意,有n件物品各自有價格,還有m種打包購買的方案,現在要買其中的若干件,求最小代價
解法:狀壓,f[i]表示已購買物品情況爲i時的最小价值,方程f[i | w[j]] = min(f[i | w[j]], f[i] + p[j]),w[j]爲第j種買法的狀壓,p[j]爲價格
注意:同一件物品可以買多次;可以買額外的物品

其中轉移可以看成圖的轉移,然後變爲求最短路,坑點在於:最後答案是多個取min(因爲可以買額外的。。) 
*/
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<deque>
using namespace std;

typedef pair<int,int> P;

const int maxn=30;
const int MAXN=1<<21;
const int maxm=2010;

int n,m;

int A[maxn];
P B[maxm];

int dis[MAXN], inq[MAXN];

void spfa(int s) {
    static deque<int> deq;
    memset(dis, 0x3f, sizeof dis);
    memset(inq, 0, sizeof inq);
    dis[s] = 0; deq.push_back(s); inq[s] = 1;
    while (!deq.empty()) {
        int u = deq.front(); deq.pop_front(); inq[u] = 0;

        for(int i=0;i<m;++i){
            int v=u|B[i].first, w=B[i].second;
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                if (!inq[v]) {
                    deq.empty() || dis[v] < dis[deq.front()] ?
                        deq.push_front(v) : deq.push_back(v);
                    inq[v] = 1;
                }
            }
        }
    }
}

void solve(){
    scanf("%d",&n);
    for(int i=0;i<n;++i)scanf("%d",&A[i]);
    scanf("%d",&m);
    for(int i=0;i<m;++i){
        int v,y;scanf("%d%d",&v,&y);
        int S=0;
        while(y--){
            int x;scanf("%d",&x); -- x;
            S|=1<<x;
        }
        B[i]=P(S,v);
    }
    for(int i=0;i<n;++i) B[m++]=P(1<<i,A[i]);
    spfa(0);
    int T=0;
    {
        int y;scanf("%d",&y);
        while(y--){
            int x;scanf("%d",&x); -- x;
            T|=1<<x;
        }
    }
    int res=0x3f3f3f3f;
    for(int S=0;S<(1<<n);++S)if((S&T)==T) res=min(res,dis[S]);
    printf("%d\n",res);
}
int main(){
//  freopen("in.txt","r",stdin);
    solve();
//  for(;;);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章