zoukankan      html  css  js  c++  java
  • test20190904 JKlover

    100+100+100=300。最后十分钟极限翻盘。

    树链剖分

    给一棵以1为根的有根树,开始只有1有标记.

    每次操作可以给某个点打上标记,或者询问从某个点开始向上跳,遇到的第一个有标记的点.

    对于 100% 的数据, n ≤ 106, m ≤ 5 × 106

    题解

    若把查询看成找树根, 发现打标记的操作相当于断边。

    那么倒着做就相当于加边了。于是用并查集维护即可。

    注意一些特殊情况:给1打标记,重复打标记。

    天气之子

    有 n 个人依次进入观影厅, 观看 Weathering with You .

    观影厅只有一排座位, 第 1 个人进入时, 会选择第 1 个座位坐下.

    由于观影厅空调坏掉了, 十分炎热, 之后的每个人进入时, 他会选择一个离最近的已经坐下的人尽可能远的空位.

    如果有多个空位使得离最近的人同样远, 则他会从其中随机选取一个.

    若有两个人选择的位置相邻, 他们就会不满意.

    为了让所有人都满意, 观影厅至少需要有几个座位呢?

    对于 100% 的数据, n ≤ 101000.

    题解

    对每个座位数能够容纳的人数进行打表可以发现,容纳人数是递增的。有个特殊的人数数列

    [A={2,3,5,9,17,33,dots,2^{n-1}+1} ]

    对于每个人数 (a_i),都对应了一段的座位数 ([n+n-1,n+2(n-1)])。这一段座位数能够容纳的人数都是 (a_i),并且两两间隔从 (1) 逐渐增大到 (2)。而对于非 (a_i) 数列中的人数,只有一个座位数的容纳人数与之相等。

    于是用高精度算一下大于等于 (n) 的最小的 (a_i),然后简单计算即可。

    打表程序

    co int N=10000+10;
    int v[N],le[N],ri[N];
    int f[N];
    int main(){
    	cout<<1<<" "<<1<<endl<<2<<" "<<1<<endl;
    	for(int n=3;n<=1000;++n){
    		fill(v+1,v+n+1,0),v[1]=v[n]=1;
    		int ans=2;
    		while(1){
    			for(int i=1;i<=n;++i) le[i]=v[i]?i:le[i-1];
    			for(int i=n;i>=1;--i) ri[i]=v[i]?i:ri[i+1];
    			int len=1,pos;
    			for(int i=1;i<=n;++i)
    				if(min(i-le[i],ri[i]-i)>len) len=min(i-le[i],ri[i]-i),pos=i;
    			if(len==1) break;
    			v[pos]=1,++ans;
    		}
    		cout<<n<<" "<<ans<<endl;
    	}
    	return 0;
    }
    

    AC 程序

    #include<bits/stdc++.h>
    using namespace std;
    template<class T> T read(){
    	T x=0,w=1;char c=getchar();
    	for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
    	for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    	return x*w;
    }
    template<class T> T read(T&x){
    	return x=read<T>();
    }
    #define co const
    #define il inline
    typedef long long LL;
    
    co int N=113,mod=1000000000;
    co int P10[10]={1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
    struct node{
    	int n,v[N];
    // 123456789123456789
    	void input(){
    		static char s[1001];
    		scanf("%s",s);int len=strlen(s);
    		reverse(s,s+len);
    		n=(len-1)/9;
    		for(int i=0;i<len;++i) v[i/9]+=P10[i%9]*(s[i]-'0');
    	}
    	void output(){
    		printf("%d",v[n]);
    		for(int i=n-1;i>=0;--i) printf("%09d",v[i]);
    	}
    	node operator+(int x){ // x=1
    		node c=*this;
    		c.v[0]+=x;
    		return c;
    	}
    	node operator-(int x){ // x=1
    		node c=*this;
    		c.v[0]-=x;
    		for(int i=0;i<=c.n;++i){
    			if(c.v[i]<0) c.v[i]+=mod,--c.v[i+1];
    			else break;
    		}
    		while(c.n&&!c.v[c.n]) --c.n;
    		return c;
    	}
    	node operator-(co node&b){ // *this>=b
    		node c=*this;
    		for(int i=0;i<=c.n;++i){
    			c.v[i]-=b.v[i];
    			if(c.v[i]<0) c.v[i]+=mod,--c.v[i+1];
    		}
    		while(c.n&&!c.v[c.n]) --c.n;
    		return c;
    	}
    	node&operator*=(int x){ // x=2
    		for(int i=0;i<=n;++i) v[i]*=x;
    		for(int i=0;i<=n;++i) v[i+1]+=v[i]/mod,v[i]%=mod;
    		if(v[n+1]) ++n;
    		return *this;
    	}
    	bool operator<(node&b){
    		if(n!=b.n) return n<b.n;
    		for(int i=n;i>=0;--i)
    			if(v[i]!=b.v[i]) return v[i]<b.v[i];
    		return 0;
    	}
    }n,a;
    
    int main(){
    	freopen("tenki.in","r",stdin),freopen("tenki.out","w",stdout);
    	n.input();
    	if(n.n==0&&n.v[0]==1) {puts("1");return 0;}
    	a.v[a.n=0]=1;
    	while(a+1<n) a*=2;
    	a=a+1;
    	node b=a-n;
    	a*=2,a=a-1,a=a-b;
    	a.output();
    	return 0;
    }
    

    层层染君色

    给定一个正整数 k , 以及一棵 n 个节点的以 1 为根的有根树, 边有长度.

    记 LCA(a, b) 表示 a 与 b 在树上的最近公共祖先, dist(a) 表示树根到 a 的距离.

    每个节点可以是黑色或白色, 初始时每个节点的颜色为白色.

    进行 m 次操作, 每次操作是以下两种形式之一:
    修改操作: 给出一个修改节点 x , 将节点 x 染上黑色. 不保证 x 在染色前为白色.
    询问操作: 给出一个询问节点 x , 记所有黑点形成的集合为 S , 求出下面式子的值:

    y∈S F(dist(LCA(x, y)))

    其中函数 F 定义为,
    F(x) = ∑i=1~Xik

    由于答案可能很大, 只需要输出答案对 P = 998244353 取模的结果.

    对于 100% 的数据, 1 ≤ n ≤ 105, 1 ≤ k < P, 0 ≤ d ≤ 107, 且保证 ∀x ∈ [1, n], dist(x) ≤ 107

    题解

    那个 F 函数只能用线性筛预处理。

    观察到询问操作只与自己到根这条链有关,那么树上统计树剖即可。注意为了在父亲处去掉自己的贡献,需要将权值设为 F(dist(x))-F(dist(fax))。

    read(K);
    p[1]=1,F[1]=1;
    for(int i=2;i<M;++i){
        if(!p[i]) p[++cnt]=i,F[i]=fpow(i,K);
        for(int j=1;j<=cnt&&i*p[j]<M;++j){
            p[i*p[j]]=1,F[i*p[j]]=mul(F[i],F[p[j]]);
            if(i%p[j]==0) break;
        }
    }
    for(int i=2;i<M;++i) F[i]=add(F[i-1],F[i]);
    
  • 相关阅读:
    差分约束
    POJ 2449 Remmarguts' Date[k短路]
    K短路
    hdu4034 Graph(floyd)
    hdu2089不要62(数位dp)
    POJ3468 A Simple Problem with Integers ( 线段树)
    POJ3255:Roadblocks(次短路 SPFA+A星)
    usaco2.1Ordered Fractions( 枚举, 数学)
    hdu1565方格取数(1) (状态压缩dp)
    poj3259 Wormholes(spfa)
  • 原文地址:https://www.cnblogs.com/autoint/p/test20190904.html
Copyright © 2011-2022 走看看