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

  • 相关阅读:
    对数可以用来简化乘法计算
    理解了一点github的用法了
    由摄氏温度和华氏温度转换想到的。
    CMD原来是支持通配符的啊
    怎么在CMD中创建文件
    如何学习数学
    SCILAB
    STS或eclipse安装SVN插件
    Html解析类的新选择CsQuery
    Tomcat编码问题
  • 原文地址:https://www.cnblogs.com/WinterSpell/p/13493901.html
Copyright © 2011-2022 走看看