zoukankan      html  css  js  c++  java
  • Codeforces Round #750 (Div.2) A~F1题解

    传送门


    这一场比赛D题想假了,结果fst。本来能涨,这下掉了12分。

    A

    有结论?A题还猜什么结论,直接留1个3,2个2,3个1暴力,时间复杂度(O(1000 * 2^6)),过了就是了。

    至于结论,是这么推出来的:令(S=a+2b+3c),即所有数的和。那么用这些数一定能凑出来([1sim S])中的任何一个整数。因为(a,b,cgeqslant 1),那么先贪心的用3凑,这样要么3没了,要么余数小于3,因此再用2和1必定能凑出来。

    那么就分成(lfloor frac{S}{2} floor)(lceil frac{S}{2} ceil)两组即可,进而得出,当(S)为奇数的时候答案为1,偶数的时候答案为0.

    代码不贴了。

    B

    水题一道,统计0的个数为(c_0),1的个数为(c_1),输出(2^{c_0} * c_1)即可。

    C

    C题稍有点意思,但也不难。

    显然对于每个字母可以单独考虑,那么枚举字母ch,然后反过来想:先把ch都删去,然后对称的贪心添加ch即可。要注意的是ch可以作为回文中心,即最中间的c不用成对的添加。

    我这代码学的略丑,推荐题解的代码。

    #include<bits/stdc++.h>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    #define forE(i, x, y) for(int i = head[x], y; ~i && (y = e[i].to); i = e[i].nxt)
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 1e5 + 5;
    In ll read()
    {
    	ll ans = 0;
    	char ch = getchar(), las = ' ';
    	while(!isdigit(ch)) las = ch, ch = getchar();
    	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
    	if(las == '-') ans = -ans;
    	return ans;
    }
    In void write(ll x)
    {
    	if(x < 0) x = -x, putchar('-');
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + '0');
    }
    
    int n;
    char s[maxn];
    
    int cnt = 0;
    char t[maxn];
    In bool check()
    {
    	for(int i = 1, j = cnt; i <= cnt; ++i, --j)
    		if(t[i] != t[j]) return 0;
    	return 1;
    }
    In int solve(char c)
    {
    	cnt = 0; int sum = 0;
    	for(int i = 1; i <= n; ++i)
    		if(s[i] != c) t[++cnt] = s[i];
    		else sum++;
    	if(!check()) return INF;
    	int suml = 0, sumr = 0;
    	int i = 1, j = n, tot = 0;
    	while(s[i] != c && i <= n) ++i, suml++;
    	while(s[j] != c && j) --j, sumr++;	
    	while(i < j)
    	{
    		if(suml == sumr)
    		{
    			tot += 2, ++i, --j;
    			while(s[i] != c && i <= n) ++i, suml++;		
    			while(s[j] != c && j) --j, sumr++;		
    		} 
    		else if(suml < sumr)
    		{
    			++i;
    			while(s[i] != c && i <= n) ++i, suml++;
    		}
    		else if(suml > sumr)
    		{
    			--j;
    			while(s[j] != c && j) --j, sumr++;
    		} 
    	}
    	if(i == j && suml == sumr) tot++;
    	return sum - tot;
    }
    
    int main()
    {
    	int T = read();
    	while(T--)
    	{
    		n = read();
    		scanf("%s", s + 1);
    		int ans = INF;
    		for(int i = 0; i < 26; ++i) ans = min(ans, solve('a' + i));
    		write(ans == INF ? -1 : ans), enter;
    	}
    	return 0;
    }
    

    D

    这题我想复杂了,还不对……

    首先当(n)是偶数的时候很好办,只要令(b_i=a_{i+1},b_{i+1}=-a_i)即可,而且这样有(sum_{i=1}^n |b_i| leqslant MAXA * MAXN = 10^9),刚好不会超题中的限制。

    (n)是奇数的时候怎么办呢?前面的三个数单独处理,后面的就变成(n)是偶数的情况。至于前面的三个数,直接令(b_1 = -a_3,b_2=-a_3,b_3=a_1+a_2)即可。但是要注意两数之和不能等于0,而这在三个数中必然存在(因为至少有两个数是同号)

    我们在算一下这种构造方法的最大值:对于后面的(n-3)个数,他们的最大值是(MAXA * (MAXN-1-3))(因为(n)是奇数,而(MAXN)是偶数,所以要多减1),而前三个数的最大值是(MAXA * (1+1+2)).把这两部分加起来,刚好就是(MAXA * MAXN=10^9),妙吧。

    而我场上的方法就比较蠢了。对于(n)是奇数的那三个数,我列出了一个不定方程,用exgcd解……虽然能解出来,但这样就不满足题目中最大值的限制了。

    给个正解的代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    #define forE(i, x, y) for(int i = head[x], y; ~i && (y = e[i].to); i = e[i].nxt)
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 1e5 + 5;
    In ll read()
    {
    	ll ans = 0;
    	char ch = getchar(), las = ' ';
    	while(!isdigit(ch)) las = ch, ch = getchar();
    	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
    	if(las == '-') ans = -ans;
    	return ans;
    }
    In void write(ll x)
    {
    	if(x < 0) x = -x, putchar('-');
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + '0');
    }
    
    int n, a[maxn];
    
    In void solve()
    {
    	int beg;
    	if(n & 1)
    	{
    		beg = 4;
    		if(a[1] + a[2]) printf("%d %d %d ", -a[3], -a[3], a[1] + a[2]);
    		else if(a[1] + a[3]) printf("%d %d %d ", -a[2], a[1] + a[3], -a[2]);
    		else printf("%d %d %d ", a[2] + a[3], -a[1], -a[1]);		
    	}
    	else beg = 1;
    	for(int i = beg; i <= n; i += 2) write(a[i + 1]), space, write(-a[i]), space;
    	enter;
    }
    
    int main()
    {
    	int T = read();
    	while(T--)
    	{
    		n = read();
    		for(int i = 1; i <= n; ++i) a[i] = read();
    		solve();
    	}
    	return 0;
    }
    

    E

    这题其实非常简单,注意到(K leqslant sqrt{2n}),因此可以直接dp。

    因为题目中序列的长度递减,所以可以倒着dp.令(dp[i][j])表示到第(i)个位置,最后一段长度为(j)时,能取到的最大值,那么就有(dp[i][j] = max{dp[i - 1][j], S(i, i + j - 1)})(需满足(S(i, i + j - 1) < dp[i + j][j - 1])

    这样(O(nsqrt{n}))就能轻松搞定了。

    而我比赛的时候就狠奇葩了:dp方程我想出来了,但是我是正的dp的。因为(K)满足单调性,所以我先二分,然后用dp检验。注意到dp的状态(应该)不是很多,所以我只把合法的状态存下来,转移的时候用单调栈优化,用时1918ms卡掉了这道题……

    我贴一个正解的代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    #define forE(i, x, y) for(int i = head[x], y; ~i && (y = e[i].to); i = e[i].nxt)
    typedef long long ll;
    typedef double db;
    const ll INF = 0x3f3f3f3f3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 1e5 + 5;
    const int maxk = 455;
    In ll read()
    {
    	ll ans = 0;
    	char ch = getchar(), las = ' ';
    	while(!isdigit(ch)) las = ch, ch = getchar();
    	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
    	if(las == '-') ans = -ans;
    	return ans;
    }
    In void write(ll x)
    {
    	if(x < 0) x = -x, putchar('-');
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + '0');
    }
    
    int n;
    ll a[maxn], sum[maxn];
    
    In ll S(int L, int R) {return sum[R] - sum[L - 1];}
    ll dp[maxn][maxk];
    In int DP()
    {
    	int K = 1;
    	while((K + 1) * (K + 2) / 2 <= n) ++K;
    	for(int i = 1; i <= K; ++i) dp[n + 1][i] = -1;
    	dp[n + 1][0] = INF;
    	for(int i = n; i; --i)
    	{
    		dp[i][0] = INF; 
    		for(int j = 1; j <= K; ++j)
    		{
    			dp[i][j] = dp[i + 1][j];
    			if(i + j - 1 <= n && S(i, i + j - 1) < dp[i + j][j - 1]) dp[i][j] = max(dp[i][j], S(i, i + j - 1));
    		}
    	} 
    	for(int i = K; i; --i) if(~dp[1][i]) return i;
    	return 0;
    }
    
    int main()
    {
    	int T = read();
    	while(T--)
    	{
    		n = read();
    		for(int i = 1; i <= n; ++i)
    		{
    			a[i] = read();
    			sum[i] = sum[i - 1] + a[i];
    		}
    		write(DP()), enter;
    	}
    	return 0;
    }
    

    还有这是我的神奇做法:

    #include<bits/stdc++.h>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    #define forE(i, x, y) for(int i = head[x], y; ~i && (y = e[i].to); i = e[i].nxt)
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 1e5 + 5;
    In ll read()
    {
    	ll ans = 0;
    	char ch = getchar(), las = ' ';
    	while(!isdigit(ch)) las = ch, ch = getchar();
    	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
    	if(las == '-') ans = -ans;
    	return ans;
    }
    In void write(ll x)
    {
    	if(x < 0) x = -x, putchar('-');
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + '0');
    }
    
    int n;
    ll a[maxn], sum[maxn];
    
    In ll S(int L, int R) {return sum[R] - sum[L - 1];}
    
    struct Node
    {
    	int pos; ll val;
    	In bool operator < (const Node& oth)const
    	{
    		return pos < oth.pos;
    	}
    };
    vector<Node> st[maxn];
    int cnt[maxn];
    In void in(int pos, int len, ll val)  //把合法的dp状态存到栈里
    {
    	int& top = cnt[len];
    	if(top && st[len][top].val <= val) return;
    	if(++top == (int)st[len].size()) st[len].push_back((Node){0, 0});
    	st[len][top] = (Node){pos, val};
    }
    In bool check(int len)
    {
    	for(int i = 1; i <= n; ++i) st[i].clear(), st[i].push_back((Node){0, 0}), cnt[i] = 0;
    	for(int i = len; i <= n; ++i)
    	{
    		in(i, len, S(i - len + 1, i));
    		int tot = len;
    		for(int j = len - 1; j; --j)
    		{
    			if(j + tot > i) break;
    			ll tp = S(i - j + 1, i); 
    			int pos = upper_bound(st[j + 1].begin(), st[j + 1].end(), (Node){i - j, 0}) - st[j + 1].begin() - 1;
    			if(pos > 0 && pos <= cnt[j + 1] && st[j + 1][pos].val < tp) in(i, j, tp);
    			tot += j;
    		}
    	}
    	return cnt[1] > 0;
    }
    
    int main()
    {
    	int T = read();
    	while(T--)
    	{
    		n = read();
    		for(int i = 1; i <= n; ++i)
    		{
    			a[i] = read();
    			sum[i] = sum[i - 1] + a[i];
    		}
    		int L = 1, R = 1;
    		while(R * (R + 1) / 2 <= n) R++;
    		R--;
    		while(L < R)
    		{
    			int mid = (L + R + 1) >> 1;
    			if(check(mid)) L = mid;
    			else R = mid - 1;
    		}
    		write(L), enter;
    	}
    	return 0;
    }
    

    F1

    F2以后再看吧,先说一下F1的思路。

    F1其实一点也不难,我也纳闷比赛的时候怎么没想出来。首先观察到(a_i leqslant 500),这就意味着异或出来的数也不超过511.因此我们用(val[i][x])表示到序列的第(i)个数,异或出(x)时,最后一个数(a_j)的最小值。那么每读一个(a_i),就判断(val[i-1][x])是否小于(a_i),是的话就可以转移到(val[i][x extrm{XOR} a_i])上。

    这样的时间复杂度是(O(500n))的。实现的时候可以省去第一维。

    看代码吧,一看就懂了。

    const int maxb = 512;
    int n, val[maxb];
    
    int main()
    {
    	n = read();
    	Mem(val, 0x3f), val[0] = 0;
    	for(int i = 1; i <= n; ++i)
    	{
    		int x = read();
    		for(int i = 0; i < maxb; ++i) if(val[i] < x) val[i ^ x] = min(val[i ^ x], x);
    	}
    	int cnt = 0;
    	for(int i = 0; i < maxb; ++i) if(val[i] != INF) ++cnt;
    	write(cnt), enter;
    	for(int i = 0; i < maxb; ++i) if(val[i] != INF) write(i), space; enter; 
    	return 0;
    }
    
  • 相关阅读:
    [Django]Windows下Django配置Apache示范设置
    《职场》笔记20061119
    Python Django还是RoR,这是一个问题
    收集证据:fsjoy.com的流氓推广和幕后流氓主子[updated]
    爱尔兰网友邀请我对Dublin交通监视器进行手机端开发
    {基于Applet的J2ME模拟器}和{microemulator}[J2ME推荐]
    中国移动IM飞信0802上线新版本 试用手记
    [AsyncHandle]什么引发了ObjectDisposedException?
    百度的“搜索背后的人”的战略
    [Python]检查你的站点的人气
  • 原文地址:https://www.cnblogs.com/mrclr/p/15463947.html
Copyright © 2011-2022 走看看