zoukankan      html  css  js  c++  java
  • bzoj 4569 [Scoi2016]萌萌哒

    4569: [Scoi2016]萌萌哒

    Time Limit: 10 Sec  Memory Limit: 256 MB
    [Submit][Status][Discuss]

    Description

    一个长度为n的大数,用S1S2S3...Sn表示,其中Si表示数的第i位,S1是数的最高位,告诉你一些限制条件,每个条
    件表示为四个数,l1,r1,l2,r2,即两个长度相同的区间,表示子串Sl1Sl1+1Sl1+2...Sr1与Sl2Sl2+1Sl2+2...S
    r2完全相同。比如n=6时,某限制条件l1=1,r1=3,l2=4,r2=6,那么123123,351351均满足条件,但是12012,13
    1141不满足条件,前者数的长度不为6,后者第二位与第五位不同。问满足以上所有条件的数有多少个。

    Input

    第一行两个数n和m,分别表示大数的长度,以及限制条件的个数。接下来m行,对于第i行,有4个数li1,ri1,li2
    ,ri2,分别表示该限制条件对应的两个区间。
    1≤n≤10^5,1≤m≤10^5,1≤li1,ri1,li2,ri2≤n;并且保证ri1-li1=ri2-li2。

    Output

     一个数,表示满足所有条件且长度为n的大数的个数,答案可能很大,因此输出答案模10^9+7的结果即可。

    Sample Input

    4 2
    1 2 3 4
    3 3 3 3

    Sample Output

    90

    Solution

    如果没有限制,没有模数的话,答案应该是9*10n,加了限制之后,有些数可以由其它数确定,相当于位数减少了

    我们需要确定有效的位数

    可以用并查集,把一样的数位看成一个连通块

    但是一个一个修改的话,很慢,是O(mn)的

    其实有些限制是没用的,最多需要修改n-1个数位的fa

    所以需要维护很多个不需要修改的区间

    可以用一个类似st表的东西,我觉得也有一点像线段树

    fa[i][j]=x表示i为左端点,2j为长度的区间的数,与x为左端点,2j为长度的区间的数对应相等

    每次修改的时候,把[l1,r1],[l2,r2]分别转化为两个这样的区间,然后依次递归到更小的区间去修改,当当前区间满足条件,或区间长度为1时停止递归

    我傻得区间左右端点都算不清了⊙︿⊙

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #define nn 100011
    using namespace std;
    const long long mod=1e9+7;
    int fa[nn][25],log_2;
    int read()
    {
    	int ans=0,f=1;char ch=getchar();
    	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)) {ans=ans*10+ch-'0';ch=getchar();}
    	return ans*f;
    }
    int find(int x,int l)
    {
    	return fa[x][l]==x? x:fa[x][l]=find(fa[x][l],l);
    } 
    void merge(int a,int b,int l)
    {
    	int f1=find(a,l),f2=find(b,l);
    	if(f1==f2) return;
    	fa[f1][l]=f2;
    	if(!l) return;
    	l--;
    	merge(a,b,l);
    	merge(a+(1<<l),b+(1<<l),l);
    }
    int main()
    {
    	long long res=9;
    	int n,m,l1,r1,l2,r2,len,num=-1;
    	n=read();m=read();
    	if(n==1)
    	{
    		printf("9");
    		return 0;
    	}
    	for(int i=1;i<=n;i++)
    	  for(int j=0;j<=18;j++)
    	    fa[i][j]=i;
    	for(int i=1;i<=m;i++)
    	{
    		l1=read();r1=read();l2=read();r2=read();
    		len=log2(r1-l1+1);
    		if(l1<l2) 
    		  swap(l1,l2),swap(r1,r2);
    		merge(l1,l2,len);merge(r1-(1<<len)+1,r2-(1<<len)+1,len);
    	}
    	for(int i=1;i<=n;i++)
    	  if(find(i,0)==i)
    	    num++;
    	for(int i=1;i<=num;i++)
    	  res=res*(long long)10%mod;
    	printf("%lld",res);
    	return 0;
    }
    /*
    5 3
    2 3 1 2
    1 5 1 5
    4 4 3 3
    */
  • 相关阅读:
    Jquery第一篇【介绍Jquery、回顾JavaScript代码、JS对象与JQ对象的区别】
    将数据转成JSON
    AJAX多级下拉联动【JSON】
    AJAX验证码检查
    生成验证码JSP【复用代码】
    AJAX二级下拉联动【XML方式】
    JavaScript总体的介绍【JavaScript介绍、定义函数方式、对象类型、变量类型】
    企业人事管理系统
    java.lang.IllegalArgumentException: node to traverse cannot be null!
    复用代码【SSH配置文件】
  • 原文地址:https://www.cnblogs.com/charlotte-o/p/7701067.html
Copyright © 2011-2022 走看看