zoukankan      html  css  js  c++  java
  • NOI-Online 2 test200425

    NOI-Online 2 test0425

    surprise mtf

    T1 涂色游戏

    题意

    你有 (10^{20}) 个格子,它们从 (0) 开始编号,初始时所有格子都还未染色,现在你按如下规则对它们染色:

    1. 编号是 (p_1)倍数的格子(包括 (0) 号格子,下同)染成红色。
    2. 编号是 (p_2) 倍数的格子染成蓝色。
    3. 编号既是 (p_1) 倍数又是 (p_2) 倍数的格子,你可以选择染成红色或者蓝色。

    其中 (p_1)(p_2) 是给定的整数,若格子编号是 (p_1)(p_2) 的倍数则它必须要被染色。在忽略掉所有未染色格子后,你不希望存在 (k) 个连续的格子颜色相同,因为你认为这种染色方案是无聊的。现在给定 (p_1,p_2,k),你想知道是否有一种染色方案不是无聊的。

    得分情况

    期望得分:100
    实际得分:0-20(luogu民间估计)
    改题得分:100

    考试想法

    真的心态崩了……公式推错了就很棒棒……没啥好讲的,样例跟……一样水。

    正解

    不妨设 (p_1<p_2),且 (p_1,p_2) 互质。

    则会发现:最坏情况,也就是从 (kp_2+1)((k+1)p_2-1)这个连续串内塞 (p_1) 所对应的颜色。

    这样就有 (dfrac{p_2-2}{p_1}+1) 个连续块,将其与 (k) 比较即可。

    因为可能不互质,所以可以两边除 (gcd(p_1,p_2)) 即可。

    T2 子序列问题

    题意

    给定一个长度为 (n) 的正整数序列 (A_1,A_2,cdots,A_n)。定义一个函数 (f(l,r)) 表示:序列中下标在 ([l,r])范围内的子区间中,不同的整数个数。换句话说,(f(l,r)) 就是集合 ${A_l,A_{l+1},cdots,A_r} $的大小,这里的集合是不可重集,即集合中的元素互不相等。

    现在,请你求出(sum_{l=1}^nsum_{r=l}^n (f(l,r))^2)。由于答案可能很大,请输出答案对 (10^9 +7) 取模的结果。

    得分情况

    期望得分:100
    实际得分:70-100(luogu民间估计)
    改题得分:100(直接开O2没有改动)

    考试想法

    正解……可能我太弱了,没算好复杂度,以为线段树可以过……

    而且可能也不是线段树的问题,我用的map,用离散化将快的飞起。

    我们从前往后递推当前位置 (i) 加入了新数 (a_i)

    对于每次加入了(a_i) 我们需要计算

    (tmp_i=sum_{l=1}^i (f(l,i))^2),然后就可以直接 (ans=ans+tmp) 了。

    怎样快速的计算(tmp)呢。

    不妨设 (b_j)(f(j,i))

    那么每次枚举到的新的 (b_i)(1)

    对于(b_j(jin[1,i-1])) ,设s为最后一次出现 (a_i) 的位置(离散化和map皆可)。

    [b_j=egin{cases} b_j+1 quad jin{[s+1,i-1]}\ b_jquadquad jin{[1,s]} end{cases}\ ]

    这个可以用 线段树 树状数组维护。

    此时我们需要计算的 (tmp_i= sum_{j=1}^ib_j^2)

    此时我们已经有了(tmp_{i-1}) ,那么我们的问题变为了怎样快速的转换 (tmp_i)

    此时,(b_j,jin[s+1,i-1]) 已经变为了(b_j+1),此时给 (tmp) 的贡献是多少呢?

    我们易知这个小学算式

    [(n +1)^2=n^2+2n+1\(n+1)^2-n^2=2n+1 ]

    每个 (b_j,jin[s+1,i-1])(tmp) 贡献了 (2b_i+1)

    我们可以直接用线段树 树状数组计算出(sss=sum_{j=s+1}^{i-1} 2b_j+1)

    那么 (tmp_i=tmp_{i-1}+sss+b_i^2) ,这里前面讲到了 (b_i=1)

    然后就可以愉快的 (ans=ans+tmp_i)了。

    这里附上一下线段树的假代码,开 O2 在Luogu 上可过……但是我肯定凉凉了……

    #include<bits/stdc++.h>
    using namespace std;
    
    #define int long long
    #define Int signed
    
    const int maxn=1e6+10;
    const int mod=1e9+7;
    
    map<int,int>ma;
    
    int n;
    
    struct sgt_tree{
    	int a[maxn<<2],f[maxn<<2];
    	
    	inline void push_up(int x){
    		a[x]=a[x<<1]+a[x<<1|1];
    		return;
    	}
    	
    	inline void push_down(int x,int l,int r){
    		if(f[x]){
    			int mid=(l+r)>>1;
    			f[x<<1]+=f[x];
    			f[x<<1|1]+=f[x];
    			a[x<<1]+=(mid-l+1)*f[x];
    			a[x<<1|1]+=(r-mid)*f[x];
    			f[x]=0;
    		}
    		return;
    	}
    
    	int sum(int x,int l,int r,int L,int R){
    		if(L>R)
    			return 0;
    		int s=0;
    		if(L<=l && r<=R)
    			s+=a[x];
    		else{
    			push_down(x,l,r);
    			int mid=(l+r)>>1;
    			if(L<=mid)
    				s+=sum(x<<1,l,mid,L,R);
    			if(mid<R)
    				s+=sum(x<<1|1,mid+1,r,L,R);
    		}
    		return s;
    	}
    
    	void add(int x,int l,int r,int L,int R){
    		int mid=(l+r)>>1;
    		if(L<=l && r<=R){
    			a[x]+=r-l+1;
    			f[x]++;
    		}
    		else{
    			push_down(x,l,r);
    			if(L<=mid)
    				add(x<<1,l,mid,L,R);
    			if(mid<R)
    				add(x<<1|1,mid+1,r,L,R);
    			push_up(x);
    		}
    		return;
    	}
    }sgt;
    
    inline int read(){
    	int x=0,c=getchar();
    	while(!isdigit(c))
    		c=getchar();
    	while(isdigit(c)){
    		x=(x<<3)+(x<<1)+c-'0';
    		c=getchar();
    	}
    	return x;
    }
    
    int ans,tmp;
    
    Int main(){
    #ifdef ZTZ_CPP
    	freopen("sequence.in","r",stdin);
    	freopen("sequence.out","w",stdout);
    #endif
    	int x;
    	scanf("%lld",&n);
    	for(register int i=1;i<=n;i++){
    		x=read();
    		int s=ma[x];
    		ma[x]=i;
    		//tmp=(tmp+i-1-s+sgt.sum(1,1,n,s+1,i-1)*2+1)%mod;
    		tmp=(tmp+i-s+sgt.sum(1,1,n,s+1,i-1)*2%mod)%mod;
    		sgt.add(1,1,n,s+1,i);
    		ans=(ans+tmp)%mod;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    正解

    用树状数组……

    T3 游戏

    题意

    小 A 和小 B 正在玩一个游戏:有一棵包含 (n=2m) 个点的有根树(点从 (1sim n)编号),它的根是 (1) 号点,初始时两人各拥有 (m) 个点。游戏的每个回合两人都需要选出一个自己拥有且之前未被选过的点,若对手的点在自己的点的子树内,则该回合自己获胜;若自己的点在对方的点的子树内,该回合自己失败;其他情况视为平局。游戏共进行 (m) 回合。

    作为旁观者的你只想知道,在他们随机选点的情况下,第一次非平局回合出现时的回合数的期望值。
    为了计算这个期望,你决定对于 (k=0,1,2,cdots,n)计算出第一次非平局回合出现在第 (k) 个回合的情况数。两种情况不同当且仅当存在一个小 A 拥有的点 (x),小 B 在 (x) 被小 A 选择的那个回合所选择的点不同。

    由于情况总数可能很大,你只需要输出答案对 (998244353) 取模后的结果。

    (n le 5000)

    得分情况

    实际得分:没写
    改题得分:

    正解

    (借用韬哥的sol搞一波)

    大概?是个玄学数学公式+树上DP吧

    树上DP可能想的到,不过真的不知道从何下手就没动了……还是太菜了……

    考试总结

    可能还是考试的时候没有多想

    第一题看到旁边人推出来了于是也急了

    发现自己的公式可以过样例就直接交了一手也没验证……

    然后T2想当然的以为map跑得快……

    一开始想过要改成离散化的

    但是由于懒了还是没去改……然后得分就这么看脸了…………

    T3可能也就没啥心情想做了

    没看出暴力怎么打于是就放弃了……

    下次考试还是要分配好时间

    简单的题目多验证几下

    然后还要多考虑优化代码,鬼晓得评测机会出什么玄学事故……

  • 相关阅读:
    PHP“Cannot use object of type stdClass as array”
    JS简单循环遍历json数组的方法
    省市区、民族下拉列表框
    java 代码获取视频时长
    CentOs 相关
    曾经遇过的sql问题
    在线分享代码
    ssm 数据库连接池配置
    代码片段
    java 常见问题
  • 原文地址:https://www.cnblogs.com/ztz-cpp/p/12773192.html
Copyright © 2011-2022 走看看