zoukankan      html  css  js  c++  java
  • CF1368F

    CF1368F

    这是一道交互题。

    Alice 和 Bob 在玩游戏,有 (n) 盏灯排成一个圈,顺时针标号为 (1sim n),初始所有灯都是关着的。

    每轮操作为:

    • Alice 选择一个 (kin [1,n]) 然后打开任意 (k) 盏灯(可以重复打开)
    • Bob 关闭一段长度为 (k) 的区间的灯。

    (R) 表示经过若干轮后开着的灯的数量的最大值。

    你需要在不超过 (10^4) 次操作达到这个上界。

    (nle 1000)

    • 请注意,灯是环形摆放。

    Solution

    (A) 表示当前亮着的灯的数量。

    假设当前增加了 (k) 盏灯,里面如果 Bob 无法消去 (k) 盏灯,那么 (A) 将会增大。

    换而言之,如果操作后不存在连续的 (k) 盏灯,那么当前操作就可以使得 (A) 增大。

    考虑 (A) 能够增大的必要条件是什么,即存在一个 (k) 使得操作后有不存在连续的 (k) 盏灯。

    注意到 (R<n),所以我们至少有一盏灯是关闭状态。

    注意到操作之后的亮着的灯的数量为 (A+k),此时仍有连续的灯的数量为 (k-1),从某个灭着的灯处看,我们发现最优情况下每隔 (k) 个位置就有一盏灯是灭着的,我们有 (A+kle n-1-frac{n-1}{k})

    所以 (Ale n-k-1-frac{n-1}{k})

    于是答案的上界为 (max_{k} (n-k-1-frac{n-1}{k})+1),即 (A) 到达上界后仍然可以增大 (1)

    考虑这样的策略,我们先固定此 (k),然后维护集合 (A) 满足 ({xin A,x e 1pmod k})

    不难证明集合中不存在连续的 (k) 个数(注意到 (1) 被 ban 掉了)

    所以我们每次操作总能够选出 (k) 个数,同时使答案至少增大 (1)

    可以证明当 (k=sqrt{n})(下取整)时得到最优解。

    (Code:)

    #include<bits/stdc++.h>
    using namespace std ;
    #define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
    #define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
    #define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
    #define re register
    int gi() {
    	char cc = getchar() ; int cn = 0, flus = 1 ;
    	while( cc < '0' || cc > '9' ) {  if( cc == '-' ) flus = - flus ; cc = getchar() ; }
    	while( cc >= '0' && cc <= '9' )  cn = cn * 10 + cc - '0', cc = getchar() ;
    	return cn * flus ;
    }
    const int N = 1000 + 5 ; 
    int n, R, Z, k, cnt, A[N] ;  
    signed main()
    {
    	fflush(stdout) ; 
    	n = gi(), k = sqrt(n) ;
    	R = n - k - (n - 1) / k ;
    	if( R <= 0 ) { puts("0") ; exit(0) ; }
    	while(1) {
    		printf("%d ", k ) ; cnt = 0 ;
    		rep( i, 1, n ) {
    			if(A[i] || i % k == 1) continue ; 
    			printf("%d ", i ), A[i] = 1, ++ Z, ++ cnt ; 
    			if( cnt == k ) break ; 
    		}
    		puts("") ; 
    		int x ; cin >> x ; 
    		rep( i, 0, k - 1 ) {
    			if( A[(i + x - 1) % n + 1] ) -- Z ;
    			A[(i + x - 1) % n + 1] = 0 ; 
    		}
    		if( Z == R ) break ; 
    	}
    	puts("0") ; 
    	return 0 ;
    }
    
  • 相关阅读:
    实体类、边界类和控制类
    面向对象分析和面向对象设计的区别
    面向对象分析与设计的步骤
    用例图:从用户角度描述系统功能,并指各功能的操作者
    面向对象分析和设计(OOA/D)
    在UML系统开发中有三个主要的模型
    UML建模之活动图介绍(Activity Diagram)
    活动图本质上就是流程图
    流程图
    流程、业务与事务
  • 原文地址:https://www.cnblogs.com/Soulist/p/13771687.html
Copyright © 2011-2022 走看看