Codeforces Round #654 (Div. 2)ABCD题解 E待补

Codeforces Round #654 (Div. 2)

A. Magical Sticks

  • 题意重述:

  • n n n个木棍长度分别为 1 − n 1-n 1n,每次操作可以合并两根木棍,得到的新木棍为原来两个木棍的长度

    • 求若干次变换后,最多数量的长度相同的木棍
  • 思路

    全部拼出长度为 n n n的木棍,答案为 ⌊ ( n + 1 ) / 2 ⌋ \lfloor (n+1)/2 \rfloor (n+1)/2

#include 

using namespace std;

void solved()
{
    int n;cin >> n;
    cout << (n + 1)/ 2 <<"\n";
}

int main()
{
#ifdef ONLINE_JUDGE
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#endif
    int t = 1;
    cin >> t;
    while(t--)
    {
        solved();
    }

#ifdef LOCAL 
    system("pause");
#endif
    return 0;
}B 

B. Magical Calendar

  • 题意重述:

    每周的天数是 1 − R 1-R 1R之间的一个数字,现在选择连续的 N N N天,在日历上将这连续的 N N N天涂上颜色

    问对于 1 − R 1-R 1R之间每周不同的天数总共有几种不一样的形状

  • 思路

    设每周的天数为 t t t,取值范围是 1 ≤ t ≤ R 1 \le t \le R 1tR

    • 如果 t ≥ N t \ge N tN ,那么连续的 N N N天都可以在一周内,每个 t t t取值得到的贡献是 t t t
    • 如果 t ≤ N t \leq N tN,那么连续的 N N N天必然在两周或更多周内,然后第一周可以选择只涂最后一个方块,也可以选择涂倒数两个方块,直到把第一周全部涂满,这样贡献也为 t t t
    • 这个时候只需要得到 t t t的范围即可,需要分类讨论
      • R ≥ N R \ge N RN时,答案为 ( 1 + k − 1 ) ∗ ( k − 1 ) / 2 + 1 (1+k-1)*(k-1)/2+1 (1+k1)(k1)/2+1
      • R < N R \lt N R<N时, 答案为 ( 1 + r ) ∗ r / 2 (1+r)*r/2 (1+r)r/2
#include 

using namespace std;
typedef long long ll;

void solved()
{
    ll n,r;
    cin >> n >> r;
    ll ans = 0;
	if(n <= r) ans++;
	ll x = min(n - 1, r);
	ans += (1 + x) * x / 2;
	cout << ans <<"\n";
}

int main()
{
#ifdef ONLINE_JUDGE
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#endif
    int t = 1;
    cin >> t;
    while(t--)
    {
        solved();
    }

#ifdef LOCAL 
    system("pause");
#endif
    return 0;
}

C. A Cookie for You

  • 题意重述:

    • 现在有香草味的饼干 v v v个,巧克力味饼干 c c c个,有两类客人
    • 第一类客人: 哪个饼干少就选择吃另外一种饼干
    • 第二类客人:哪种饼干少就吃哪种饼干
    • 现在问是否所有客人都有饼干吃
  • 思路

    • 首先判断饼干总数是否够吃

    • 然后只需要判断第二类客人是否能满足即可

#include 

using namespace std;
typedef long long ll;

void solved()
{
    ll a,b,n,m;
    cin >> a >> b >> n >> m;
    if(a + b < n + m)
    {
        cout << "No\n";
        return;
    }
    ll t = min(a,b);
    if(t >= m)
    {
        cout <<"Yes\n";
    }
    else cout <<"No\n";
}

int main()
{
#ifdef ONLINE_JUDGE
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#endif
    int t = 1;
    cin >> t;
    while(t--)
    {
        solved();
    }

#ifdef LOCAL 
    system("pause");
#endif
    return 0;
}

D. Grid-00100

  • 题意重述

    • 给定一个 N N N N N N列的全0矩阵,需要让其中的k个0变成1,然后使最大列和最小列的差值以及最大行和最下行的差值的平方和最小
    • 最小化 ( m a x c − m i n c ) 2 + ( m a x r − m i n r ) 2 (maxc-minc)^2+(maxr-minr)^2 (maxcminc)2+(maxrminr)2
  • 思路

    赛时想到的构造方法是先填充对角线,这样可以保证最优

    然后仔细思考其实对角线是从 ( 0 , 0 ) (0,0) (0,0)开始到 ( 1 , 1 ) , ( 2 , 2 ) , ( 3 , 3 ) , ( 4 , 4 ) . . . ( n − 1 , n − 1 ) (1,1),(2,2),(3,3),(4,4)...(n-1,n-1) (1,1),(2,2),(3,3),(4,4)...(n1,n1),

    第二条对角线从(0,1)开始到 ( 1 , 2 ) , ( 2 , 3 ) , ( 3 , 4 ) . . . ( n − 1 , n ) (1,2),(2,3),(3,4)...(n-1,n) (1,2),(2,3),(3,4)...(n1,n),然而这里第 n n n列是无法出现的,然后我们惊奇的发现 n n n列对 n n n取模后得到的答案就是 0 0 0,所以我们将 ( n − 1 , n ) (n-1,n) (n1,n)取模成 ( n − 1 , 0 ) (n-1,0) (n1,0)这样的构造也是最优的选择

    后面依次类推即可~保证最优解

#include 

using namespace std;

char s[301][301];

int main()
{
#ifdef ONLINE_JUDGE
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#endif
    int t = 1;
    cin >> t;
    while(t--)
    {
    int n, ssk;
	cin >> n >> ssk;

	for(int k = 0; k < n; k++) 
		for(int i = k, j = 0; j < n; i++, j++) {
			if(ssk > 0) s[i % n][j] = '1', ssk--;
			else s[i % n][j] = '0';
		}
	for(int i = 0; i < n; i++) s[i][n] = '\0'; 
	int maxr = 0, minr = n, Maxc = 0, minc = n;
	
    for(int i = 0; i < n; i++) { 
		int tem = 0;
		for(int j = 0; j < n; j++)
			tem += s[i][j] - '0';
		maxr = max(maxr, tem);
		minr = min(minr, tem); 
	}
	
	for(int j = 0; j < n; j++) {
		int tem = 0;
		for(int i = 0; i < n; i++)
			tem += s[i][j] - '0';
		Maxc = max(Maxc, tem);
		minc = min(minc, tem);
	}
	int res = (maxr - minr) * (maxr - minr) + (Maxc - minc) * (Maxc - minc);
	
    cout << res <<"\n";
	for(int i = 0; i < n; i++)
		cout << s[i] <<"\n"; 
    }

#ifdef LOCAL 
    system("pause");
#endif
    return 0;
}

你可能感兴趣的:(cf题解)