• 2015-2016 Petrozavodsk Winter Training Camp, Nizhny Novgorod SU Contest (5/9)


    2015-2016 Petrozavodsk Winter Training Camp, Nizhny Novgorod SU Contest

    B. Forcefield

    题意

    给你一维平面上n个镜子,镜子的朝向有正面和背面,如果光束从正面穿过,会摧毁镜子,并且光束会反向;如果从背面穿过的话,什么都不会发生。

    光束一开始从X位置,射向0点,然后你人在0点,会反射光束。

    问你要破坏所有镜子,人需要反弹光束多少次。

    数据范围100000

    题解

    其实模拟就好了,击破镜子的顺序就那么一种。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5+6;
    const int inf = 1e9+1;
    set<int> s1,s2;
    int n,x[maxn],p[maxn];
    set<int>::iterator it;
    int main()
    {
        scanf("%d%d",&n,&x[0]);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&x[i],&p[i]);
            if(p[i]==1)s1.insert(x[i]);
            if(p[i]==0)s2.insert(x[i]);
        }
        s2.insert(0);
        s1.insert(0);
        s2.insert(inf);
        s1.insert(inf);
        int now = x[0],flag=2;
        int ans = 0;
        while(1)
        {
            if(flag==2){
                int pos = *--s2.lower_bound(now);
                if(pos==0){
                    ans++;
                    now=pos;
                }
                else{
                    s2.erase(pos);
                    now=pos;
                }
                flag=1;
            }else{
                int pos = *s1.upper_bound(now);
                if(pos==inf){
                    if(s1.size()==2&&s2.size()==2)
                        break;
                    printf("-1
    ");
                    return 0;
                }else{
                    s1.erase(pos);
                    now=pos;
                }
                flag=2;
            }
        }
        cout<<ans<<endl;
    }
    

    C.Missing Part

    题意

    给你一个串S,这个S是环状的,给你另外一个字符串S1。

    给你大写的ABCDE和小写的abcde,然后你需要定义一种对应关系,使得失配数最小。

    题解

    假设只有两种字符,那么就是FFT了。

    然后这个是5个嘛,最粗鲁的做法是120个FFT。

    优化一下 就是25个FFT就好了。

    队友写的,实验细节不知道。

    代码

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int maxn = 5e4 + 50;
    char s1[maxn << 1],s2[maxn];
    int n ,ans,f[15],use[15];
    vector < int > pos[5] , ano[5];
    
    const double PI = acos(-1.0);
    //复数结构体
    struct Complex
    {
        double r,i;
        Complex(double _r = 0.0,double _i = 0.0)
        {
            r = _r; i = _i;
        }
        Complex operator +(const Complex &b)
        {
            return Complex(r+b.r,i+b.i);
        }
        Complex operator -(const Complex &b)
        {
            return Complex(r-b.r,i-b.i);
        }
        Complex operator *(const Complex &b)
        {
            return Complex(r*b.r-i*b.i,r*b.i+i*b.r);
        }
    };
    /*
     * 进行FFT和IFFT前的反转变换。
     * 位置i和 (i二进制反转后位置)互换
     * len必须去2的幂
     */
    void change(Complex y[],int len)
    {
        int i,j,k;
        for(i = 1, j = len/2;i < len-1; i++)
        {
            if(i < j)swap(y[i],y[j]);
            //交换互为小标反转的元素,i<j保证交换一次
            //i做正常的+1,j左反转类型的+1,始终保持i和j是反转的
            k = len/2;
            while( j >= k)
            {
                j -= k;
                k /= 2;
            }
            if(j < k) j += k;
        }
    }
    /*
     * 做FFT
     * len必须为2^k形式,
     * on==1时是DFT,on==-1时是IDFT
     */
    void fft(Complex y[],int len,int on)
    {
        change(y,len);
        for(int h = 2; h <= len; h <<= 1)
        {
            Complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h));
            for(int j = 0;j < len;j+=h)
            {
                Complex w(1,0);
                for(int k = j;k < j+h/2;k++)
                {
                    Complex u = y[k];
                    Complex t = w*y[k+h/2];
                    y[k] = u+t;
                    y[k+h/2] = u-t;
                    w = w*wn;
                }
            }
        }
        if(on == -1)
            for(int i = 0;i < len;i++)
                y[i].r /= len;
    }
    
    int len = 131072;
    
    Complex X[131075],Y[131075];
    
    int ret[5][5][maxn];
    
    void predeal(){
        for(int i = 0 ; i < 5 ; ++ i)
    		for(int j = 0 ; j < 5 ; ++ j){
    			memset( X , 0 , sizeof( X ) );
    			memset( Y , 0 , sizeof( Y ) );
    			int x = i , y = j;
    			for(auto it : pos[i]) X[it+1].r++;
    			for(auto it : ano[y]) Y[n-it].r++;
    			fft( X , len , 1 );
    			fft( Y , len , 1 );
    			for(int j = 0 ; j < len ; ++ j) X[j] = X[j] * Y[j];
    			fft( X , len , -1 );
    			for(int k = n + 1 ; k <= 2 * n ; ++ k) ret[i][j][k - n] += (int)(X[k].r + 0.5);
    		}
    }
    
    void cal_ans(){
    	for(int i = 1 ; i <= n ; ++ i){
    		int sum = 0;
    		for(int j = 0 ; j < 5 ; ++ j)
    			sum += ret[j][f[j]][i];
    		ans = max( ans , sum );
    	}
    }
    
    void DFS( int x ){
    	if( x == 5 ){
    		cal_ans();
    	}else{
    		for(int i = 0 ; i < 5 ; ++ i)
    			if(!use[i]){
    				f[x] = i;
    				use[i] = 1;
    				DFS( x + 1 );
    				use[i] = 0;
    			}
    	}
    }
    
    int main(int argc , char * argv[] ){
    	freopen("in.txt","r",stdin);
    	scanf("%s%s",s1,s2);
    	n=strlen(s1);
    	for(int i = 0 ; i < n ; ++ i) s1[i + n] = s1[i];
    	for(int i = 0 ; i < (n * 2) ; ++ i) pos[s1[i] - 'A'].push_back( i );
    	for(int i = 0 ; i < n ; ++ i) ano[s2[i] - 'a'].push_back( i );
    	predeal();
    	DFS( 0 );
    	printf("%d
    ",n-ans);
    	return 0;
    }
    

    The Jedi Killer

    题意

    平面上给你三个点,然后给你三条线段的长度,两条为lg,一条为lm。

    三条线段的一个端点都在同一个位置,且lg垂直于lm。

    问你这三个线段是否能够覆盖题目所给的三个点。

    题解

    丝薄题,XJB判一判就好了。

    就三种情况,lm穿过两个点,lg穿过两个点,或者三点共线。

    判判判就好了。

    代码

    #include<bits/stdc++.h>
    
    using namespace std;
    
    struct point
    {
        long long x,y;
    }p[3];
    
    long long cross(point p1,point p2,point p0)
    {
        return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
    }
    long long dist2(point p1,point p2)
    {
        return (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y);
    }
    
    void solve()
    {
        long long lg,lm;
        cin>>lm>>lg;
        for(int i=0;i<3;i++)
            cin>>p[i].x>>p[i].y;
        if(cross(p[0],p[1],p[2])==0)
        {
            long long tmp=max(lm*lm,lg*lg*4LL);
            if(dist2(p[0],p[1])<=tmp&&dist2(p[1],p[2])<=tmp&&dist2(p[2],p[0])<=tmp)
                printf("YES
    ");
            else
                printf("NO
    ");
            return ;
        }
        for(int i=0;i<3;i++)
        {
            for(int j=i+1;j<3;j++)
            {
                for(int k=0;k<3;k++)
                    if(k!=i&&k!=j)
                    {
                        int flag=1;
                        long long a=p[i].y-p[j].y,b=p[j].x-p[i].x;
                        long long c=-a*p[i].x-b*p[i].y;
                        long long tmp=(a*p[k].x+b*p[k].y+c)*(a*p[k].x+b*p[k].y+c);
                        if(lm*lm*(a*a+b*b)<tmp) flag=0;
                        if(dist2(p[i],p[k])*(a*a+b*b)-tmp>lg*lg*(a*a+b*b)) flag=0;
                        if(dist2(p[j],p[k])*(a*a+b*b)-tmp>lg*lg*(a*a+b*b)) flag=0;
                        if(flag)
                        {
                            printf("YES
    ");
                            return ;
                        }
                        flag=1;
                        if((dist2(p[i],p[j])+dist2(p[i],p[k])-dist2(p[j],p[k]))>0&&(dist2(p[i],p[j])+dist2(p[j],p[k])-dist2(p[i],p[k]))>0) flag=0;
                        if(lg*lg*(a*a+b*b)<tmp) flag=0;
                        if(dist2(p[i],p[k])*(a*a+b*b)-tmp>lm*lm*(a*a+b*b)) flag=0;
                        if(dist2(p[j],p[k])*(a*a+b*b)-tmp>lm*lm*(a*a+b*b)) flag=0;
                        if(flag)
                        {
                            printf("YES
    ");
                            return ;
                        }
                    }
            }
        }
        printf("NO
    ");
    }
    
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)solve();
        return 0;
    }
    

    G. Youngling Tournament

    题意

    给你n个数,然后从大到小排序,如果这个数不小于他后面的数的和,那么这个数就是胜利者。

    单点修改,问你每次胜利者有多少个。

    题解

    其实就是问你f[i]+sum[i]>=sum[n]的有多少个。

    实际上就是区间修改+单点修改+查询区间第k大。

    分块莽莽莽,然后再调一调常数就好了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 2e5+7;
    inline long long read()
    {
        long long x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int n,N,m,num,belong[maxn],x[maxn],block,l[maxn],r[maxn],flag[maxn],p[maxn];
    long long a[maxn],val[maxn],c[maxn];
    long long sum[maxn],B[2000];
    long long d[maxn];
    map<long long,int> H;
    int use[maxn],cnt;
    vector<int>E[maxn];
    int getid(long long x)
    {
        if(H[x])return H[x];
        if(!H[x])H[x]=++cnt;
        return H[x];
    }
    vector<long long> V;
    void build()
    {
        N=V.size();
        block=sqrt(N/2);
        num=N/block;if(N%block)num++;
        for(int i=1;i<=num;i++)
            l[i]=(i-1)*block+1,r[i]=i*block;
        r[num]=N;
        for(int i=1;i<=N;i++)
            belong[i]=(i-1)/block+1;
        int tot = 1;
        for(int i=1;i<=N;i++)
            E[getid(a[i])].push_back(i);
        for(int i=1;i<=n;i++)
            flag[E[getid(c[i])][use[getid(c[i])]++]]=1;
    }
    void build(int l,int r)
    {
        int id=belong[l];B[id]=0;
        for(int i=l;i<=r;i++)d[i]=0,sum[i]=0;
        for(int i=l;i<=r;i++)
        {
            if(i!=l)sum[i]=sum[i-1];
            if(flag[i]==1){
                sum[i]+=a[i];
                B[id]+=a[i];
                d[i]=a[i]+sum[i];
            }else{
                d[i]=-1e9;
            }
        }
        sort(d+l,d+r+1);
    }
    void query()
    {
        long long Sum = 0;
        for(int i=1;i<=num;i++)
            Sum+=B[i];
        long long tmp = 0;
        int ans = 0;
        for(int i=1;i<=num;i++)
        {
            int L=l[i],R=r[i],Ans=r[i]+1;
            while(L<=R)
            {
                int mid=(L+R)/2;
                if(d[mid]+tmp>=Sum)Ans=mid,R=mid-1;
                else L=mid+1;
            }
            ans+=(r[i]-Ans+1);
            tmp+=B[i];
        }
        printf("%d
    ",ans);
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            a[i]=read();c[i]=a[i];
            V.push_back(a[i]);
        }
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            p[i]=read();val[i]=read();
            V.push_back(val[i]);
        }
        sort(V.begin(),V.end());
        reverse(V.begin(),V.end());
        for(int i=0;i<V.size();i++)
            a[i+1]=V[i];
        build();
        for(int i=1;i<=num;i++)
            build(l[i],r[i]);
        query();
        for(int i=1;i<=m;i++)
        {
            int pos = E[getid(c[p[i]])][--use[getid(c[p[i]])]];
            flag[pos]=0;
            build(l[belong[pos]],r[belong[pos]]);
            c[p[i]]=val[i];
            pos=E[getid(c[p[i]])][use[getid(c[p[i]])]++];
            flag[pos]=1;
            build(l[belong[pos]],r[belong[pos]]);
            query();
        }
    }
    

    H. Garland Checking

    题意

    强制在线,给你一棵树

    三个操作:

    连接a,b

    切掉a,b

    查询a,b之间是否有边。

    题解

    裸LCT

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    const int MAXN = 200010;
    struct Node {
        Node *ch[2], *p; int size, value;
        bool rev;
        Node(int t = 0);
        inline bool dir(void) {return p->ch[1] == this;}
        inline void SetC(Node *x, bool d) {
            ch[d] = x; x->p = this;
        }
        inline void Rev(void) {
            swap(ch[0], ch[1]); rev ^= 1;
        }
        inline void Push(void) {
            if (rev) {
                ch[0]->Rev();
                ch[1]->Rev();
                rev = 0;
            }
        }
        inline void Update(void) {
            size = ch[0]->size + ch[1]->size + 1;
        }
    }Tnull, *null = &Tnull, *fim[MAXN];
    // 要记得额外更新null的信息
    Node::Node(int _value){ch[0] = ch[1] = p = null; rev = 0;}
    inline bool isRoot(Node *x) {return x->p == null || (x != x->p->ch[0] && x != x->p->ch[1]);}
    inline void rotate(Node *x) {
        Node *p = x->p; bool d = x->dir();
        p->Push(); x->Push();
        if (!isRoot(p)) p->p->SetC(x, p->dir()); else x->p = p->p;
        p->SetC(x->ch[!d], d);
        x->SetC(p, !d);
        p->Update();
    }
    inline void splay(Node *x) {
        x->Push();
        while (!isRoot(x)) {
            if (isRoot(x->p)) rotate(x);
            else {
                if (x->dir() == x->p->dir()) {rotate(x->p); rotate(x);}
                else {rotate(x); rotate(x);}
            }
        }
        x->Update();
    }
    inline Node* Access(Node *x) {
        Node *t = x, *q = null;
        for (; x != null; x = x->p) {
            splay(x); x->ch[1] = q; q = x;
        }
        splay(t); //info will be updated in the splay;
        return q;
    }
    inline void Evert(Node *x) {
        Access(x); x->Rev();
    }
    inline void link(Node *x, Node *y) {
        Evert(x); x->p = y;
    }
    inline Node* getRoot(Node *x) {
        Node *tmp = x;
        Access(x);
        while (tmp->Push(), tmp->ch[0] != null) tmp = tmp->ch[0];
        splay(tmp);
        return tmp;
    }
    // 一定要确定x和y之间有边
    inline void cut(Node *x, Node *y) {
        Access(x); splay(y);
        if (y->p != x) swap(x, y);
        Access(x); splay(y);
        y->p = null;
    }
    inline Node* getPath(Node *x, Node *y) {
        Evert(x); Access(y);
        return y;
    }
    inline void clear(void) {
        null->rev = 0; null->size = 0; null->value = 0;
    }
    
    int judge(Node *x,Node *y)
    {
        while(x->p!=null)x = x->p;
        while(y->p!=null)y = y->p;
        if(x!=y)return 0;
        return 1;
    }
    int main()
    {
        clear();
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
            fim[i] = new Node();
        string c;
        int u,v;
        while(1)
        {
            cin>>c;
            if(c[0]=='E')break;
            cin>>u>>v;
            if(c[0]=='T')
            {
                if(judge(fim[u],fim[v]))
                    cout<<"YES"<<endl;
                else
                    cout<<"NO"<<endl;
            }
            else if(c[0]=='C')
                link(fim[u],fim[v]);
            else
                cut(fim[u],fim[v]);
        }
    }
  • 相关阅读:
    Mysql 多字段去重
    一个不错的PHP二维数组排序函数简单易用存用
    关于威富通的微信扫码支付处理思路和流程
    牛顿迭代法求解平方根
    impex 语法
    屏幕取词技术实现原理与关键源码
    支持向量机通俗导论(理解SVM的三层境界)
    用 Chrome 扩展实现修改
    可编辑表格
    在浏览器右键添加自定义菜单
  • 原文地址:https://www.cnblogs.com/qscqesze/p/6022143.html
Copyright © 2020-2023  润新知