1. 程式人生 > >ACM-ICPC國際大學生程式設計競賽北京賽區(2015)網路賽

ACM-ICPC國際大學生程式設計競賽北京賽區(2015)網路賽

補題。

列舉圓心點,然後二分半徑。注意圓的邊上不能有點。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
const double eps=1e-8;

int sign(double x){
    return (x>eps)-(x<-eps);
}
double sqr(double x){return x*x;}

struct Point{
    double x,y;
    void input(){
        scanf("%lf%lf",&x,&y);
    }
}p[111];

double dist(Point a,Point b){
    return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
}

int check(int n,int m,int idx,double R){
    int cnt=0;
    for(int i=0;i<n;i++){
        if(sign(dist(p[idx],p[i])-R)<0) cnt++;
    }
    return cnt;
}

int main(){
    int T;scanf("%d",&T);
    while(T--){
        int n,m;scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++) p[i].input();
        int mi=400000;
        for(int i=0;i<n;i++){
            int L=0,R=40000,ans=-1;
            while(L<=R){
                int mid=(L+R)>>1;
                int tmp=check(n,m,i,mid);
                if(tmp>=m){
                    if(tmp==m) ans=mid;
                    R=mid-1;
                }else L=mid+1;
            }
            if(ans!=-1){
                for(int j=0;j<n;j++){
                    if(sign(dist(p[i],p[j])-ans)==0) ans=-1;
                }
            }
            if(ans!=-1) mi=min(ans,mi);
        }
        if(mi==400000) printf("%d\n",-1);
        else printf("%d\n",mi);
    }
}

B-Mission Impossible 6

模擬一下就好了,據說如果V的時候長度超多限制,就不用貼上。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 20000;
char s[maxn];
char ans[maxn];
int m;
int cnt;
int pos = 0;
string clipboard = "";
int copyStuts = 0;//nothing
int copPosition = -1;
int mode = 0;// insert

void delet(){
    int len = 0;
    if(copyStuts == 0) {
        if(pos == cnt) {
            return;
        }
        for(int i = pos; i < cnt - 1; i ++) {
            ans[i] = ans[i + 1];
        }
        cnt --;
    }else {
        if(pos >= copPosition) {
            len = pos - copPosition;
            for(int i = copPosition; i + len < cnt; i ++) {
                ans[i] = ans[i + len];
            }
            pos = copPosition;
            copyStuts = 0;
            copPosition = -1;
            cnt -= len;
        }else {
            len = copPosition - pos;
            for(int i = pos; i + len < cnt; i ++) {
                ans[i] = ans[i + len];
            }
            copyStuts = 0;
            copPosition = -1;
            cnt -= len;
        }
    }
}

void backup() {
    if(pos == 0) return;
    pos --;
    for(int i = pos; i < cnt - 1; i ++) {
        ans[i] = ans[i + 1];
    }
    cnt --;
}

void paste(){
    int len = clipboard.size();
    if(mode == 0) {
        if(cnt + len > m) return;
        for(int i = cnt - 1; i >= pos; i --) {
            ans[i + len] = ans[i];
        }
        for(int i = 0; i < len; i ++) {
            ans[i + pos] = clipboard[i];
        }
        pos = pos + len;
        cnt += len;
    }else{
        if(pos + len > m) return;
        for(int i = 0; i < len; i ++) {
            ans[i + pos] = clipboard[i];
        }
        pos = pos + len;
        cnt = max(cnt, pos);
    }
}

int main(){
    int t;
    scanf("%d", &t);
    while(t --) {
        memset(ans, 0, sizeof ans);
        memset(s, 0, sizeof s);
        scanf("%d%s", &m, s);

        cnt = 0;
        pos = 0;
        clipboard = "";
        copyStuts = 0;//nothing
        copPosition = -1;
        mode = 0;// insert

        for(int i = 0; s[i]; i ++) {
            if(s[i] == 'S') {
                copyStuts = 0;
                copPosition = -1;
                mode = 1 - mode;
            }else if(s[i] == 'L') {
                pos = max(0, pos - 1);
            }else if(s[i] == 'R') {
                pos = min(cnt, pos + 1);
            }else if(s[i] == 'D') {
                delet();
            }else if(s[i] == 'B') {
                copyStuts = 0;
                copPosition = -1;
                backup();
            }else if(s[i] == 'C') {
                if(copyStuts == 0) {
                    copyStuts = 1;
                    copPosition = pos;
                }else{
                    clipboard = "";
                    for(int i = min(copPosition, pos); i < max(copPosition, pos); i ++) {
                        clipboard += ans[i];
                    }
                    copyStuts = 0;
                    copPosition = -1;
                }
            }else if(s[i] == 'V') {
                paste();
                copyStuts = 0;
                copPosition = -1;
            }else{
                copyStuts = 0;
                copPosition = -1;
                if(mode == 0) {
                    if(cnt + 1 > m) continue;
                    for(int i = cnt - 1; i >= pos; i --) {
                        ans[i + 1] = ans[i];
                    }
                    ans[pos] = s[i];
                    pos = pos + 1;
                    cnt += 1;
                }else{
                    if(pos + 1 > m) continue;
                    ans[pos] = s[i];
                    pos = pos + 1;
                    cnt = max(cnt, pos);
                }
            }
        }


        if(cnt == 0) {
            puts("NOTHING");
            continue;
        }
        for(int i = 0; i < cnt; i ++) {
            printf("%c", ans[i]);
        }
        puts("");
    }
    return 0;
}

C-Protecting Homeless Cats

佔坑。

很容易想到可以列舉x,然後就變成了n*2+1個在區間[x,x+m]中的數字異或為0的種數。裸的轉移是n^3的dp,但是可以用FWT加速複雜度變為mlogm。

學FWT可以去這裡NIM那道題。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int MOD = 1000000007;

LL PowMod(LL a, LL n)
{
    LL ret = 1;
    while(n)
    {
        if(n & 1) ret = ret * a % MOD;
        a = a * a % MOD;
        n >>= 1;
    }
    return ret;
}

LL a[1<<11];
LL Inv2 = PowMod(2, MOD - 2);

void Transform(int l, int r, LL a[]) /// [l, r)
{
    if(l == r - 1) return ;
    int len = (r - l) >> 1;
    int m = l + len;
    Transform(l, m, a);
    Transform(m, r, a);
    for(int i = l; i < m; i ++)
    {
        LL x1 = a[i], x2 = a[i + len];
        a[i] = (x1 - x2 + MOD) % MOD;
        a[i + len] = (x1 + x2) % MOD;
    }
}

void ReTranform(int l, int r, LL a[])
{
    if(l == r - 1) return ;
    int len = (r - l) >> 1;
    int m = l + len;
    for(int i = l; i < m; i ++)
    {
        LL y1 = a[i], y2 = a[i + len];
        a[i] = (y1 + y2) * Inv2 % MOD;
        a[i + len] = (y2 - y1 + MOD) * Inv2 % MOD;
    }
    ReTranform(l, m, a);
    ReTranform(m, r, a);
}

void Conv(LL a[], LL b[], int len)
{
    Transform(0, len, a);
    Transform(0, len, b);
    for(int i = 0; i < len; i ++)
        a[i] = a[i] * b[i] % MOD;
    ReTranform(0, len, a);
}

int n, m, L, R;

void solve()
{
    LL ans = 0;
    for(int i = L; i <= R; i ++)
    {
        CLR(a, 0);
        for(int j = i; j <= i + m; j ++)
            a[j] = 1;
        Transform(0, 1 << 11, a);
        for(int j = 0; j < (1 << 11); j ++)
        {
            a[j] = PowMod(a[j], n * 2 + 1);
        }
        ReTranform(0, 1 << 11, a);
        ans += a[0]; ans %= MOD;
    }
    printf("%lld\n", ans);
}

int main()
{
    while(scanf("%d%d%d%d", &n, &m, &L, &R) != EOF)
    {
        solve();
    }
    return 0;
}
E-Border Length

這題其實就是一個水題,要求的是圓和普通多邊形相交的圖形的邊長。顯然可以先把多邊形所有線段在院內的求出來,然後再把圓弧在多邊形裡面的求出來就好了(據說圓被多邊形完全包圍的話,圓不算?)。第一個很容易求,第二個的話有兩種方法。

方法一:暴力,因為n只有1000所以可以求出所有線段和圓交點,然後以圓心做極角排序,然後暴力判斷每個弧是否在多邊形內就好了(用弧中點)。

方法二:對於多邊形的每條邊,兩個點和圓心構成一個三角形,判斷三角形和圓的相交情況,算出所有有向弧長,然後相加取絕對值就好了。詳情參見簡單多邊形和圓相交面積

///n^2做法
#include<math.h>
#include<vector>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const double eps=1e-8;
const double pi=acos(-1.0);
const int maxn=1111;

double sqr(double x) {
    return x*x;
}
int sign(double x) {
    return (x>eps)-(x<-eps);
}

struct Point {
    double x,y;
    Point(double _x=0,double _y=0) {
        x=_x,y=_y;
    }
    Point operator+(const Point &a) {
        return Point(x+a.x,y+a.y);
    }
    Point operator-(const Point &a) {
        return Point(x-a.x,y-a.y);
    }
    Point operator*(const double &a) {
        return Point(x*a,y*a);
    }
    Point operator/(const double &a) {
        return Point(x/a,y/a);
    }
    double operator*(const Point &a) {
        return x*a.y-y*a.x;
    }
    double operator^(const Point &a) {
        return x*a.x+y*a.y;
    }
    double len() {
        return sqrt(x*x+y*y);
    }
    void input() {
        scanf("%lf%lf",&x,&y);
    }
    bool friend operator<(const Point &a,const Point &b) {
        if(sign(a.x-b.x)==0) return a.y<b.y;
        return a.x<b.x;
    }
} p[maxn],cir;

struct Event {
    Point tp;
    double angle;
    friend bool operator<(const Event &a,const Event &b) {
        return a.angle<b.angle;
    }
    bool operator==(const Event &a) {
        return sign(angle-a.angle)==0;
    }
};

vector<Event> vec;

double R;

double mult(Point a,Point b,Point c) {
    return (a.x-c.x)*(b.y-c.y)-(a.y-c.y)*(b.x-c.x);
}

double dist(Point a,Point b) {
    return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
}

double p_to_l(Point p,Point u,Point v) {
    return fabs(mult(p,u,v))/dist(u,v);
}

bool pnt_on_seg(Point p,Point l1,Point l2){
    return ((l1-p)^(l2-p))<eps;
}

int intersection_line_circle(Point p,Point v,Point cir,double R,vector<Point> &sol) {
    double a=v.x,b=p.x-cir.x,c=v.y,d=p.y-cir.y;
    double e=a*a+c*c,f=2*(a*b+c*d),g=b*b+d*d-R*R;
    double delta=f*f-4*e*g;
    if(sign(delta)<0) return 0;
    double t1,t2;
    Point p1,p2;
    if(sign(delta)==0) {
        t1=t2=-f/(2.0*e);
        p1=p+v*t1;
        sol.push_back(p1);
        return 1;
    }
    t1=(-f-sqrt(delta))/(2.0*e);
    p1=p+v*t1;
    sol.push_back(p1);
    t2=(-f+sqrt(delta))/(2.0*e);
    p2=p+v*t2;
    sol.push_back(p2);
    return 2;
}

bool isin_circle(Point p,Point cir,double R) {
    return sign(R-dist(p,cir))>0;
}

double calc(int n) {
    double ret=0;
    for(int i=0; i<n; i++) {
        if(sign(p_to_l(cir,p[i],p[i+1])-R)>0) continue;
        Point p1,p2;
        vector<Point> v,vc;
        vc.push_back(p[i]);
        vc.push_back(p[i+1]);
        int m=intersection_line_circle(p[i],p[i]-p[i+1],cir,R,v);
        for(int j=0; j<m; j++) {
            if(pnt_on_seg(v[j],p[i],p[i+1])) {
                Event tmp;
                tmp.tp=v[j];
                double angle=atan2(v[j].y-cir.y,v[j].x-cir.x);
                tmp.angle=angle;
                vec.push_back(tmp);
                vc.push_back(v[j]);
            }
        }
        sort(vc.begin(),vc.end());
        for(int j=0; j+1<vc.size(); j++) {
            Point mid=(vc[j]+vc[j+1])*0.5;
            if(isin_circle(mid,cir,R)) ret+=dist(vc[j],vc[j+1]);
        }
    }
    return ret;
}

int inside(Point p[],int n,Point t){
    int cnt=0;
    for(int i=0;i<n;i++){
        Point p1=p[i];
        Point p2=p[(i+1)%n];
        if(pnt_on_seg(t,p1,p2)&&sign((p1-t)*(p2-t))==0) return 2;
        if(sign(p1.y-p2.y)==0) continue;
        if(t.y<min(p1.y,p2.y)) continue;
        if(sign(t.y-max(p1.y,p2.y))>=0) continue;
        double x=(t.y-p1.y)*(p2.x-p1.x)/(p2.y-p1.y)+p1.x;
        if(x>t.x) cnt++;
    }
    return cnt%2==1;
}

Point getMid(Event a,Event b,double R) {
    double tmp=(a.angle+b.angle)*0.5;
    return Point(cos(tmp),sin(tmp))*R;
}

double gao(int n) {
    for(int i=0; i<=n; i++) p[i]=p[i]-cir;
    for(int i=0; i<vec.size(); i++) {
        vec[i].tp=vec[i].tp-cir;
    }
    Event tmp;
    tmp.tp=Point(-R,0);
    tmp.angle=pi;
    vec.push_back(tmp);
    tmp.tp=Point(-R,0);
    tmp.angle=-pi;
    vec.push_back(tmp);
    cir=Point(0,0);
    sort(vec.begin(),vec.end());
    vec.erase(unique(vec.begin(),vec.end()),vec.end());
    double ret=0;
    int sz=vec.size();
    for(int i=0; i+1<sz; i++) {
        Point mid=getMid(vec[i],vec[i+1],R);
        if(inside(p,n,mid)) ret+=fabs(vec[i+1].angle-vec[i].angle)*R;
    }
    return ret;
}

int main() {
    int n;
    while(scanf("%d",&n),n) {
        for(int i=0; i<n; i++) p[i].input();
        p[n]=p[0];
        cir.input();
        scanf("%lf",&R);
        vec.clear();
        double seg=calc(n);
        double rad=gao(n);
        printf("%.f\n",seg+rad);
    }
}
///O(n)做法
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const double pi=acos(-1.0);
const double eps=1e-6;

double sqr(double x){return x*x;}
int sign(double x){
    return (x>eps)-(x<-eps);
}
struct Point{
    double x,y;
    Point(double _x=0,double _y=0){
        x=_x,y=_y;
    }
    Point operator+(const Point &a){
        return Point(x+a.x,y+a.y);
    }
    Point operator-(const Point &a){
        return Point(x-a.x,y-a.y);
    }
    double operator*(const Point &a){
        return x*a.y-y*a.x;
    }
    double operator^(const Point &a){
        return x*a.x+y*a.y;
    }
    Point operator*(const double &a){
        return Point(x*a,y*a);
    }
    Point operator/(const double &a){
        return Point(x/a,y/a);
    }
    double vlen(){
        return sqrt(x*x+y*y);
    }
    void input(){
        scanf("%lf%lf",&x,&y);
    }
    void output(){
        printf("%f %f\n",x,y);
    }
}p[2000],cir,res[2000];

double x_mult(Point sp, Point ep, Point op){
    return (sp.x-op.x)*(ep.y-op.y)-(sp.y-op.y)*(ep.x-op.x);
}
double cross(Point a,Point b,Point c){
    return (a.x-c.x)*(b.x-c.x)+(a.y-c.y)*(b.y-c.y);
}
double dist(Point a,Point b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

double cal_area(Point a,Point b,Point c,double r){
    double A,B,C,x,y,tS;
    A=dist(b,c);
    B=dist(a,c);
    C=dist(b,a);
    int f;
    if(sign(A-r)<0&&sign(B-r)<0){
        return 0;
    }else if(sign(A-r)<0&&sign(B-r)>=0){
        x=(cross(a,c,b)+sqrt(r*r*C*C-x_mult(a,c,b)*x_mult(a,c,b)))/C;
        tS=x_mult(a,b,c)/2;
        return asin(tS*(1-x/C)*2/r/B)*r;
    }else if(sign(A-r)>=0&&sign(B-r)<0){
        y=(cross(b,c,a)+sqrt(r*r*C*C-x_mult(b,c,a)*x_mult(b,c,a)))/C;
        tS=x_mult(a,b,c)/2;
        return asin(tS*(1-y/C)*2/r/A)*r;
    }else if(sign(fabs(x_mult(a,b,c))-r*C)>=0||sign(cross(b,c,a))<=0||sign(cross(a,c,b))<=0){
        if(cross(a,b,c)<0)
            if(x_mult(a,b,c)<0)
                return (-acos(-1.0)-asin(x_mult(a,b,c)/A/B))*r;
            else return (acos(-1.0)-asin(x_mult(a,b,c)/A/B))*r;
        else return asin(x_mult(a,b,c)/A/B)*r;
    }else{
        x=(cross(a,c,b)+sqrt(r*r*C*C-x_mult(a,c,b)*x_mult(a,c,b)))/C;
        y=(cross(b,c,a)+sqrt(r*r*C*C-x_mult(b,c,a)*x_mult(b,c,a)))/C;
        tS=x_mult(a,b,c)/2;
        return (asin(tS*(1-x/C)*2/r/B)+asin(tS*(1-y/C)*2/r/A))*r;
    }
}

double solve(Point p[], int n, Point cir, double r){
    double area=0;
    for(int i=0;i<n;i++){
        area+=cal_area(p[i], p[(i+1)%n], cir, r);
    }
    return area;
}
Point intersection(Point u1,Point u2,Point v1,Point v2){
    double t=((u1-v1)*(v1-v2))/((u1-u2)*(v1-v2));
    return u1+(u2-u1)*t;
}
bool pnt_on_seg(Point p,Point l1,Point l2){
    return ((l1-p)^(l2-p))<eps;
}

void intersection_line_circle(Point c,double r,Point l1,Point l2,Point& p1,Point& p2){
    Point p=c;
    double t;
    p.x+=l1.y-l2.y;p.y+=l2.x-l1.x;
    p=intersection(p,c,l1,l2);
    t=sqrt(r*r-dist(p,c)*dist(p,c))/dist(l1,l2);
    p1=p+(l2-l1)*t;
    p2=p-(l2-l1)*t;
}

double p_to_line(Point p,Point u,Point v){
    return fabs((u-p)*(v-p))/dist(u,v);
}

int main(){
    int n;
    while(scanf("%d",&n),n){
        for(int i=0;i<n;i++) p[i].input();
        p[n]=p[0];
        double r;
        cir.input();scanf("%lf",&r);
        double ans=0;
        for(int i=0;i<n;i++){
            double tmp=0;
            if(sign(dist(p[i],cir)-r)<=0&&sign(dist(p[i+1],cir)-r)<=0){
                tmp=dist(p[i+1],p[i]);
            }else if(sign(p_to_line(cir,p[i],p[i+1])-r)<0){
                Point p1,p2;
                intersection_line_circle(cir,r,p[i],p[i+1],p1,p2);
                if(pnt_on_seg(p1,p[i],p[i+1])&&pnt_on_seg(p2,p[i],p[i+1])){
                    tmp=dist(p1,p2);
                }else if(pnt_on_seg(p1,p[i],p[i+1])&&!pnt_on_seg(p2,p[i],p[i+1])){
                    if(sign(dist(p[i],cir)-r)<=0) tmp=dist(p1,p[i]);
                    else tmp=dist(p[i+1],p1);
                }else if(!pnt_on_seg(p1,p[i],p[i+1])&&pnt_on_seg(p2,p[i],p[i+1])){
                    if(sign(dist(p[i],cir)-r)<=0) tmp=dist(p2,p[i]);
                    else tmp=dist(p[i+1],p2);
                }
            }
            ans+=tmp;
        }
        ans+=fabs(solve(p,n,cir,r));
        printf("%.f\n",ans);
    }
}



這題還是挺不錯的。首先對於第一顆樹,計算每個點的dfs序。那麼對於第二顆樹v節點說,第一顆樹中節點u和v的最近相交點,是u在樹1的祖先,和v在樹2的祖先。那麼,判斷v的祖先p是否是u的祖先,可以用p的dfs序的覆蓋區間(即p的子樹dfs序的區間)來判斷。顯然是求離v最近的祖先p,包括u點。這個可以在樹2上動態建一顆持久化線段樹來維護當前路徑中每個節點u最近是被哪個父親節點p覆蓋。由於要求的最近,所以每次更新的時候直接進行區間覆蓋就好了。

說的太爛,看程式碼吧。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define INF 0x3f3f3f3f
#define xx first
#define yy second
//#define lson l, m, rt << 1
//#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 100100;
const int maxm = maxn * 80;

vector<int> G1[maxn], G2[maxn];
int L[maxn], R[maxn], tot;
int seg[maxm], lson[maxm], rson[maxm];
int sz, T[maxn];
int dep1[maxn], dep2[maxn];

int n, m;

void dfs1(int u)
{
    L[u] = tot ++;
    for(int i = 0; i < G1[u].size(); i ++)
    {
        int v = G1[u][i];
        dep1[v] = dep1[u] + 1;
        dfs1(v);
    }
    R[u] = tot - 1;
}

int node()
{
    lson[sz] = rson[sz] = -1;
    seg[sz] = 0;
    return sz ++;
}

int build(int l, int r)
{
    int root = node();
    seg[root] = 1;
    return root;
}

void down(int rt)
{
    if(seg[rt])
    {
        if(lson[rt] == -1)
            lson[rt] = node();
        seg[lson[rt]] = seg[rt];
        if(rson[rt] == -1)
            rson[rt] = node();
        seg[rson[rt]] = seg[rt];
        seg[rt] = 0;
    }
}

int update(int rt, int u, int l, int r)
{
    int root = node();
    if(L[u] <= l && r <= R[u])
    {
        seg[root] = u;
        return root;
    }
    int m = (l + r) >> 1;
    down(rt);
    if(L[u] <= m && R[u] > m)
    {
        lson[root] = update(lson[rt], u, l, m);
        rson[root] = update(rson[rt], u, m + 1, r);
    }
    else if(L[u] <= m)
    {
        lson[root] = update(lson[rt], u, l, m);
        rson[root] = rson[rt];
    }
    else
    {
        lson[root] = lson[rt];
        rson[root] = update(rson[rt], u, m + 1, r);
    }
    return root;
}

int query(int rt, int q, int l, int r)
{
    if(seg[rt]) return seg[rt];
    int m = (l + r) >> 1;
    if(q <= m) return query(lson[rt], q, l, m);
    return query(rson[rt], q, m + 1, r);
}

void dfs2(int u, int fa)
{
    for(int i = 0; i < G2[u].size(); i ++)
    {
        int v = G2[u][i];
        dep2[v] = dep2[u] + 1;
        T[v] = update(T[u], v, 1, n);
        dfs2(v, u);
    }
}

void solve()
{
    tot = 1;
    dep2[1] = dep1[1] = 0;
    dfs1(1);
    sz = 1;
    T[1] = build(1, n);
    dfs2(1, 0);
    int ans = 0;
    while(m --)
    {
        int u, v; scanf("%d%d", &u, &v);
        u = (ans + u) % n + 1;
        v = (ans + v) % n + 1;
        ans = query(T[v], L[u], 1, n);
        printf("%d %d %d\n", ans, dep1[u] - dep1[ans] + 1, dep2[v] - dep2[ans] + 1);
    }
}

int main()
{
    while(scanf("%d%d", &n, &m) != EOF)
    {
        for(int i = 1; i <= n; i ++)
        {
            G1[i].clear(); G2[i].clear();
        }
        for(int i = 2; i <= n; i ++)
        {
            int v; scanf("%d", &v);
            G1[v].push_back(i);
        }
        for(int i = 2; i <= n; i ++)
        {
            int v; scanf("%d", &v);
            G2[v].push_back(i);
        }
        solve();
    }
    return 0;
}

G-Boxes

由於狀態數很少,所以直接預處理出所有答案就好了。狀態s表示的是,s的第i位表示i這個數在的位置。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define INF 0x3f3f3f3f
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 8 * 1e6;

int dp7[maxn];
int dp[7][666669];
int a[10], b[10];

void bfs(int n, int s, int dp[])
{
    dp[s] = 0;
    queue<int> Q;
    Q.push(s);
    while(!Q.empty())
    {
        int u = Q.front(); Q.pop();
        int tmp = u;
        for(int i = n; i >= 1; i --)
        {
            a[i] = tmp % 10;
            tmp /= 10;
        }
        vector<int> vec[10];
        for(int i = 1; i <= n; i ++)
        {
            vec[a[i]].push_back(i);
        }
        for(int i = 1; i <= n; i ++)
        {
            int sz = vec[i].size();
            if(sz == 0) continue;
            if(i != 1 && (vec[i - 1].size() == 0 || vec[i - 1][0] > vec[i][0]))
            {
                int v = 0;
                for(int j = 1; j <= n; j ++)
                {
                    if(j == vec[i][0])
                        v = v * 10 + i - 1;
                    else v = v * 10 + a[j];
                }
                if(dp[v] == -1)
                {
                    dp[v] = dp[u] + 1;
                    Q.push(v);
                }
            }
            if(i != n && (vec[i + 1].size() == 0 || vec[i + 1][0] > vec[i][0]))
            {
                int v = 0;
                for(int j = 1; j <= n; j ++)
                {
                    if(j == vec[i][0])
                        v = v * 10 + i + 1;
                    else v = v * 10 + a[j];
                }
                if(dp[v] == -1)
                {
                    dp[v] = dp[u] + 1;
                    Q.push(v);
                }
            }
        }
    }
}

void init()
{
    CLR(dp, -1); CLR(dp7, -1);
    for(int i = 1; i <= 7; i ++)
    {
        int s = 0;
        for(int j = 1; j <= i; j ++)
            s = s * 10 + j;
        if(i == 7) bfs(i, s, dp7);
        else bfs(i, s, dp[i]);
    }
}

int main()
{
    init();
    int T; scanf("%d", &T);
    while(T --)
    {
        int n, m = 0;
        scanf("%d", &n);
        for(int i = 0; i < n; i ++)
        {
            scanf("%d", &a[i]);
            b[i] = a[i];
        }
        sort(b, b + n);
        for(int i = 0; i < n; i ++)
        {
            a[i] = lower_bound(b, b + n, a[i]) - b + 1;
        }
        for(int i = 0; i < n; i ++)
        {
            b[a[i]] = i + 1;
        }
        for(int i = 1; i <= n; i ++)
            m = m * 10 + b[i];
        if(n == 7) printf("%d\n", dp7[m]);
        else printf("%d\n", dp[n][m]);
    }
    return 0;
}

H-Fractal

簽到題。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define INF 0x3f3f3f3f
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

double eps = 1e-10;

double k;

int sign(double x){
    return (x>eps)-(x<-eps);
}

void solve()
{
    int cnt = 1;
    double L = 0.0, R = 0.5;
    if(sign(R - k) == 0)
    {
        puts("1000");
        return ;
    }
    if(sign(k) == 0)
    {
        puts("-1");
        return ;
    }
    for(int i = 1; i <= 500; i ++)
    {
        double mid = (L + R) / 2;
        if(sign(mid - k) == 0)
        {
            puts("-1");return ;
        }
        if(sign(mid - k) > 0)
        {
            printf("%d\n", cnt * 4);
            return ;
        }
        L = mid; cnt ++;
    }
    puts("1000");
}

int main()
{
    int T; scanf("%d", &T);
    while(T --)
    {
        scanf("%lf", &k);
        solve();
    }
    return 0;
}
I-New Teaching Buildings

佔坑

這題太噁心了,暴力開的話記憶體根本開不下。所以需要求的時候實時求一點。比賽的時候感覺複雜度可能不太行。就沒仔細調。。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define INF 0x3f3f3f3f
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 50010;

#include<bitset>
bitset<maxn> dp[5][510], tmp, tmp2;

int n, m, q;
int a[5][maxn];
int id[5][maxn], t, sz[5][maxn];

bool cmp(int i, int j)
{
    return a[t][i] < a[t][j];
}

inline int get_int(){
	int ret=0;char c;
	while(!isdigit(c=getchar()));
	do {ret = (ret<<3)+(ret<<1)+c-'0';
	}while(isdigit(c=getchar()));
	return ret;
}

void solve()
{
    CLR(sz, 0);
    for(int i = 0; i < 5; i ++)
    {
        t = i;
        for(int j = 1; j <= n; j ++)
            id[i][j] = j, sz[i][a[i][j]] ++;
        sort(id[i] + 1, id[i] + n + 1, cmp);
        for(int j = 1; j <= m; j ++)
            sz[i][j] += sz[i][j - 1];
        for(int j = 0; j <= 501; j ++) dp[i][j].reset();
        for(int j = 1; j <= n; j ++)
        {
            if(j % 100 == 0)
            {
                dp[i][j / 100] = dp[i][j / 100 - 1];
                for(int k = j - 99; k <= j; k ++)
                    dp[i][j / 100][id[i][k]] = 1;
            }
        }
    }
    scanf("%d", &q);
    int ans = 0;
    while(q --)
    {
        int ask[6];
        for(int j = 0; j < 5; j ++)
        {
            ask[j] = get_int();
            ask[j] ^= ans;
        }
        tmp = dp[0][sz[0][ask[0]] / 100];
        for(int i = sz[0][ask[0]] / 100 * 100 + 1; i <= sz[0][ask[0]]; i ++)
            tmp[id[0][i]] = 1;
        for(int j = 1; j < 5; j ++)
        {
            tmp2 = dp[j][sz[j][ask[j]] / 100];
            for(int i = sz[j][ask[j]] / 100 *100 + 1; i <= sz[j][ask[j]]; i ++)
                tmp2[id[j][i]] = 1;
            tmp &= tmp2;
        }
        printf("%d\n", ans = tmp.count());
    }
}


int main()
{
    int T; scanf("%d", &T);
    while(T --)
    {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i ++)
        {
            for(int j = 0; j < 5; j ++)
                a[j][i] = get_int();
        }
        solve();
    }
    return 0;
}