zoukankan      html  css  js  c++  java
  • UOJ NOI Round #4补题

    本人两天总共拿到40分 喜提倒数第一+胸牌 本人成功拉低了整条街的智商

    序列妙妙值
    为什么全场都会这道题
    我这题得了40分,欧耶
    还是做过极其类似的题,还写过blog,结果还是不会做
    (O(kn^2))暴力:(dp_{i,j})表示前(i)个数分为(j)
    (O(knv))做法:记录前缀异或和为(x)的最优解(f_x)
    记录(val_{i,j})表示前缀异或和前(8)位为(i) 当查询的时候前缀异或和后八位为(j)时能对应的最优解
    这样每次先查询然后修改 复杂度单次都是(sqrt v)

    #include<bits/stdc++.h>
    using namespace std;
    #define fp(i,l,r) for(register int (i)=(l);i<=(r);++(i))
    #define fd(i,l,r) for(register int (i)=(l);i>=(r);--(i))
    #define fe(i,u) for(register int (i)=front[(u)];(i);(i)=e[(i)].next)
    #define mem(a) memset((a),0,sizeof (a))
    #define O(x) cerr<<#x<<':'<<x<<endl
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    void wr(int x){
        if(x<0)putchar('-'),x=-x;
        if(x>=10)wr(x/10);
        putchar('0'+x%10);
    }
    const int S=(1<<8)-1;
    int n,K,val[1<<8][1<<8],dp[9][60010],a[60010];
    inline void ins(int i,int j){
    	if(dp[i][j]>=1e9)return;
    	const int L=a[j]&S,R=a[j]>>8;
    	fp(k,0,S)val[L][k]=min(val[L][k],dp[i][j]+((R^k)<<8));
    }
    inline int ask(int j){
    	const int L=a[j]&S,R=a[j]>>8;
    	int res=1e9;
    	fp(k,0,S)res=min(res,val[k][R]+(L^k));
    	return res;
    }
    main(){
    	n=read();K=read();
    	fp(i,1,n)a[i]=read()^a[i-1];
    	fp(i,0,8)fp(j,0,n)dp[i][j]=1e9;
    	dp[0][0]=0;
    	fp(i,1,K){
    		fp(j,0,S)fp(k,0,S)val[j][k]=1e9;
    		fp(j,i,n){
    			ins(i-1,j-1);
    			dp[i][j]=ask(j);
    		}
    	}
    	fp(i,K,n)wr(dp[K][i]),putchar(' ');
    	puts("");return 0;
    }
    

    网络恢复
    以后再说。。
    好像可以给每个点随机个权值(a_i) 如果有一个点(x)度数1 那么存在一个点(y)使得(b_y=a_x)(b_x=a_y)
    校园闲逛
    谢谢rank1爷$E答疑解惑
    定义一个多项式矩阵(A) (A_{i,j})是一个多项式 (x^k)项表示从(i)(j)有多少条长度为(k)的边
    可以发现(A^k)表示走(k)条边对应的方案数
    要求(B=sum_i A^i=frac{1}{1-A})
    即对(1-A)这个矩阵求逆
    不会(O(v(n^3+n^2logv))) 只实现了(O(n^3vlogv))常数还极差 只有70分 哎
    同构判定鸭
    谢谢rank1爷$E答疑解惑
    如果存在解且解非无穷,则长度不超过(n1+n2+1) 但没看懂如何证明。。
    一个字符串的hash值是(prod A[S_i][|S|-i]) (A)是一个随机的数组
    这样就可以在前面加字符了
    每次尝试在字符串前多加一个字符判定是否出现次数相同
    若不再相同
    http://uoj.ac/submission/425140 不过好像加单向边就可以
    己酸集合
    先照着官方题解抄一遍
    写出圆方程(x^2_i+(y_i−z_i)^2≤R^2_i)
    移项得到(x^2_i+y^2_i≤R^2_i−z^2_i+2y_iz_i)
    如果我们把((x_i,y_i))映射到((y_i,x^2_i+y^2_i)),则问题转化为询问直线(l:kx+b)以下的点个数。其中(k=2z_i,b=R^2_i−z^2_i)
    然后这个我又不会做了。。
    当询问的直线的斜率(k)逐渐变大时 考虑将斜率为(k)的直线从下往上平移的过程中任意两个点(A)(B)谁会先到该直线下方
    (k)极小时显然横坐标小的点会先到直线下方 当然横坐标相同时比较纵坐标就行 以这个标准给点排序
    将任意两个点之间斜率排序(横坐标相同别管了) 这个斜率即是横坐标大的点先到直线下方时的临界值
    有两个:恶心的地方是点坐标可能相同,三点可能贡献(我要死了)
    有个神奇的处理方法。。将斜率排序时 第一个点的原排名作为第二关键字 第二个点的原排名作为第三关键字
    说白了就是要用稳定排序 我个zz
    然后要交换的时候如果第一个点排到第二个点后面去了就别交换了
    没有完全理解。。
    时间复杂度(O((n^2+Q)log n)) 不太平衡 要想到对点序列分块(然而我就想不到) 块大小取(O(sqrt Q))最优
    然后我这个脑残二分时设了l初值为0

    #include<bits/stdc++.h>
    using namespace std;
    #define fp(i,l,r) for(register int (i)=(l);(i)<=(r);++(i))
    #define fd(i,l,r) for(register int (i)=(l);(i)>=(r);--(i))
    #define fe(i,u) for(register int (i)=front[(u)];(i);(i)=e[(i)].next)
    #define mem(a) memset((a),0,sizeof (a))
    #define O(x) cerr<<#x<<':'<<x<<endl
    #define int long long
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    void wr(int x){
        if(x<0)putchar('-'),x=-x;
        if(x>=10)wr(x/10);
        putchar('0'+x%10);
    }
    const int MAXN=12010,MAXM=1e6+10;
    struct poi{
    	int x,y;
    	inline friend bool operator<(const poi &a,const poi &b){
    		if(a.x==b.x)return a.y<b.y;
    		return a.x<b.x;
    	}
    }a[MAXN],b[MAXN];
    struct line{
    	int k,b,id;
    	inline friend bool operator<(const line &a,const line &b){
    		return a.k<b.k;
    	}
    }q[MAXM];
    struct node{
    	int x,y;double k;
    	inline friend bool operator<(const node &a,const node &b){
    		if(a.k==b.k)return a.x==b.x?a.y<b.y:a.x<b.x;
    		return a.k<b.k;
    	}
    }c[MAXM];
    int n,Q,B,ans[MAXM],pos[MAXN];
    inline void Swap(int x,int y){
    	if(pos[x]>pos[y])return;
    	swap(b[pos[x]],b[pos[y]]);
    	swap(pos[x],pos[y]);
    } 
    inline void solve(int n){
    	sort(b+1,b+1+n);
    	int tot=0;
    	fp(i,1,n)fp(j,i+1,n)if(b[i].x!=b[j].x){
    		double k=1.0*(b[i].y-b[j].y)/(b[i].x-b[j].x);
    		c[++tot]={i,j,k};
    	}
    	sort(c+1,c+1+tot);
    	fp(i,1,n)pos[i]=i;
    	int p=0;
    	fp(i,1,Q){
    		int k=q[i].k,B=q[i].b,id=q[i].id;
    		while(p<tot&&c[p+1].k<k)++p,Swap(c[p].x,c[p].y);
    		int l=1,r=n,res=0;
    		//fp(i,2,n)assert(b[i-1].y-k*b[i-1].x<=b[i].y-k*b[i].x);
    		while(l<=r){
    			int mid=l+r>>1;
    			if(k*b[mid].x+B>=b[mid].y)l=mid+1,res=mid;
    			else r=mid-1;
    		} 
    		ans[id]+=res;
    	}
    }
    main(){
    	//freopen("ex_circle2.in","r",stdin);freopen("circle.out","w",stdout);
    	n=read();Q=read();B=sqrt(Q);
    	fp(i,1,n){
    		int x=read(),y=read();
    		a[i].x=y;a[i].y=x*x+y*y;
    	}
    	fp(i,1,Q){
    		int z=read(),r=read();
    		q[i].k=2*z;q[i].b=r*r-z*z;q[i].id=i;
    	}
    	sort(q+1,q+1+Q);
    	for(int l=1,r;l<=n;l=r+1){
    		r=min(n,l+B-1);
    		fp(i,l,r)b[i-l+1]=a[i];
    		solve(r-l+1);
    	}
    	fp(i,1,Q)wr(ans[i]),putchar('
    ');
    	return 0;
    }
    

    挑战哈密顿
    只会把题解复制粘贴一遍了
    维护边的一个尽量大子集,满足只考虑这些边时每个点出入度都不超过1,且不构成圈。
    如果子集大小达到n−1,则找到了一条哈密顿路。
    考虑调整维护子集。按随机顺序考虑边,如果加入后不构成圈,且加入之后所有点度数均仍合法,则加入这条边。
    否则如果不构成圈,但有一个点度数不合法,则以一半概率加入并把该点相连的与新加入边矛盾的边断掉。
    用最暴力的方法实现,也能总用时在10秒左右跑出前9个点,10分钟左右跑出最后一个点。
    dmy神发代码了:http://peehs-moorhsum.blog.uoj.ac/blog/6384

  • 相关阅读:
    leetcode Super Ugly Number
    leetcode Find Median from Data Stream
    leetcode Remove Invalid Parentheses
    leetcode Range Sum Query
    leetcode Range Sum Query
    leetcode Minimum Height Trees
    hdu 3836 Equivalent Sets
    hdu 1269 迷宫城堡
    hud 2586 How far away ?
    poj 1330 Nearest Common Ancestors
  • 原文地址:https://www.cnblogs.com/misaka10047/p/13493901.html
Copyright © 2011-2022 走看看