Codeforces Round #713 (Div. 3)题解

题目链接

这一场打的中规中矩吧,毕竟人均五题。

A题

题意:给你一个数组,数组中只有两种数值,找出只出现一次的数值的下标。

思路:显然只有整个字符串全是'a'才无解,否则对字符串进行扫描,对称位置不是'a'的地方放'a'即可。
代码如下

int n;
int a[N];
map<int, int> mp;
 
int main()
{
	IOS;
	int T;
	cin >> T;
	while(T --)
	{
		mp.clear();
		cin >> n;
		for(int i = 1 ; i <= n ; i ++)
		{
			cin >> a[i];
			mp[a[i]] ++;
		}
		int num;
		for(auto x : mp)
			if(x.y == 1)
			{
				num = x.x;
				break;
			}
		for(int i = 1 ; i <= n ; i ++)
			if(num == a[i])
			{
				cout << i << endl;
				break;
			}
	}
 
	return 0;
}

B题

这题我开始看错题了,以为要构造的是正方形,wa了两发,我真sb。
题意:给你一个\(n * n\)的图, 其中有两个''符号,让你构造一个边与图的边平行的矩形,''位于该矩形的四个顶点上。

思路:显然只需要根据给出的两个点的位置,分类判断一下。
代码如下

int n;
char g[N][N];
int main()
{
	IOS;
	int T;
	cin >> T;
	while(T --)
	{
		cin >> n;
		for(int i = 1 ; i <= n ; i ++)
			cin >> g[i] + 1;
		int a, b, c, d;
		int cnt = 0;
		for(int i = 1 ; i <= n ; i ++)
			for(int j = 1 ; j <= n ; j ++)
			{
				if(g[i][j] == '*' && !cnt)
					a = i, b = j, cnt ++;
				else if(g[i][j] == '*') c = i, d = j;
			}
		if(a == c || b == d)
		{
			int sub = 1;
			if(a == c)
			{
				if(a + sub <= n)
					g[a + sub][b] = g[c + sub][d] = '*';
				else
					g[a - sub][b] = g[c - sub][d] = '*';
			}
			else	// b == d
			{
				if(b + sub <= n)
					g[a][b + sub] = g[c][d + sub] = '*';
				else
					g[a][b - sub] = g[c][d - sub] = '*';
			}
		}
		else
		{
			g[a][d] = '*';
			g[c][b] = '*';
		}
	
		for(int i = 1 ; i <= n ; i ++)
		{
			for(int j = 1 ; j <= n ; j ++)
				cout << g[i][j];
			cout << endl;			
		}
	}
 
	return 0;
}

C题

题意:给你一个01字符串,其中包含'?','?'可以转化为0或者1,现在问你能不能将所给字符串转换成恰好含有a个0和b个1的字符串

思路:首先直接贪心地把确定位置给确定了,比如当前位置是'1',那么对称位置一定得是'1',如果是'?'直接变'1',否则无解。
然后看能不能将剩下的'?'转换成想要的0和1即可,具体看如下代码。
代码如下

int a, b;
char s[N];
 
int main()
{
	IOS;
	int T;
	cin >> T;
	while(T --)
	{
		cin >> a >> b;
		cin >> s + 1;
		int len = strlen(s + 1);
		int cnt = 0;
		bool flag = false;	//是否是奇数位中心是问号 
		bool res = true;
		for(int i = 1 ; i <= (a + b + 1) / 2 ; i ++)
		{
			int r = len - i + 1;
			if(s[i] != '?')
			{
				if(s[r] != '?')
				{
					if(s[i] != s[r])
					{
						res = false;
						break;						
					}
				}
				else
					s[r] = s[i];
			}
			else if(s[r] != '?')
			{
				if(s[i] != '?')
				{
					if(s[i] != s[r])
					{
						res = false;
						break;						
					}
				}
				else
					s[i] = s[r];				
			}
			else
			{
				if(((a + b) & 1) && i == r)	cnt ++;
				else cnt += 2;
			}
		}
		int cnt0 = 0, cnt1 = 0;
		for(int i = 1 ; i <= a + b ; i ++)
		{
			if(s[i] == '0') cnt0 ++;
			else if(s[i] == '1') cnt1 ++;			
		}
		if(cnt0 > a || cnt1 > b) res = false;
		if(res)
		{
			cnt0 = a - cnt0;
			cnt1 = b - cnt1;
			for(int i = 1 ; i <= (a + b + 1) / 2 ; i ++)
			{
				if(s[i] == '?')
				{
					int r = len - i + 1;
					if(i == r)
					{
						if(cnt0)	s[i] = '0', cnt0 --;
						else if(cnt1) s[i] = '1', cnt1 --;
					}
					else if(cnt0 > 1)
					{
						s[i] = s[r] = '0';
						cnt0 -= 2;
					}
					else if(cnt1 > 1)
					{
						s[i] = s[r] = '1';
						cnt1 -= 2;
					}				
				}
			}			
		}
		if(cnt0 || cnt1) res = false;
		if(!res) cout << -1 << endl;
		else cout << s + 1 << endl;
	}
 
	return 0;
}

D题

题意:给你一个长度为\(n + 2\)的数组,现在让你从中选择\(n\)个数字,使得剩下两个的其中一个是所选择的所有数字之和。

思路:显然不能选择最大的一个数字,直接排序,然后\(O(n)\)枚举。
代码如下

int n;
ll a[N];
ll s[N];
 
int main()
{
	IOS;
	int T;
	cin >> T;
	while(T --)
	{
		cin >> n;
		for(int i = 1 ; i <= n + 2 ; i ++)
			cin >> a[i];
		sort(a + 1, a + n + 3);
		for(int i = 1 ; i <= n + 1 ; i ++)
			s[i] = a[i] + s[i - 1];
		
		int d = 0;
		for(int i = 1 ; i <= n + 1 ; i ++)
		{
			if(s[n + 1] - a[i] == a[i] || s[n + 1] - a[i] == a[n + 2])
			{
				d = i;
				break;
			}			
		}
 
		
		if(!d) cout << -1 << endl;
		else
		{
			for(int i = 1 ; i <= n + 1 ; i ++)
			{
				if(i == d) continue;
				cout << a[i] << " ";				
			}
			cout << endl;
		}
	}
 
	return 0;
}

E题

题意:有一个长度为n的排列,现在问你能不能找到这个排列的一个形式A,使得它的\(\sum_{i = l}^rA[i] = s\)

思路:显然在确定的区间长度下,能凑出来的数有一个最大值和最小值,如果在这个区间内,显然是有解的。
有解情况下的构造方式见代码。
代码如下

int n;
int s[N];
bool st[N];
 
int main()
{
	IOS;
	int T;
	cin >> T;
	while(T --)
	{
		int n, l, r, s;
		cin >> n >> l >> r >> s;
		
		int mind = 0, maxd = 0;
		for(int i = 1 ; i <= r - l + 1 ; i ++)
			mind += i;
		for(int i = n ; i >= n - (r - l) ; i --)
			maxd += i;
		int len = r - l + 1;
		if(s >= mind && s <= maxd)
		{
			int c = (s - mind) / len;
			int left = (s - mind) % len;
			int d = 0;
			for(int i = len ; i >= 1 ; i --)
				if(i + c + left <= n)
				{
					st[i + c + left] = true;
					d = i;
					break;
				}
			for(int i = 1 ; i <= len ; i ++)
			{
				if(i == d) continue;
				st[i + c] = true;
			}
			
			int cnt = 0, now;
			for(now = 1 ; now <= n ; now ++)
			{
				if(cnt + 1 == l) break;
				if(!st[now])
					cout << now << " ", cnt ++;
			}
			
			for(int i = 1 ; i <= n ; i ++)
				if(st[i])
					cout << i << " ";
			
			for(; now <= n ; now ++)
			{
				if(!st[now])
					cout << now << " ";
			}
			cout << endl;
			memset(st, false, sizeof st);
		}
		else cout << -1 << endl;
	}
 
	return 0;
}

F题

题意:有n个位置,在每个位置每天有一个收益a[i],位置越靠近后面收益越高。同时每个位置有一个到达该位置所需要的花费,从第2个位置开始,到达该位置需要花费一定的费用b[i]。某人最开始在位置1,拥有的金钱为0,它可以待在当前位置,同时也可以通过一定的花费到达下一个位置,但只能一级一级到达。他想获得收益c的所需要的最少的天数。注意升级到下一个位置需要花费一天时间,并且不获得收益。

思路:首先明确一点,如果最优解是需要升级的,那么一定是在可以升级的时候就立马升级为最优,因此直接枚举最快到达各个等级下获得c的收益的天数,取最小值即可。
代码如下

int n, c;
ll a[N], b[N];

int main()
{
    IOS;
    int T;
    cin >> T;
    while(T --)
    {
		cin >> n >> c;
		for(int i = 1 ; i <= n ; i ++) cin >> a[i];
		for(int i = 1 ; i < n ; i ++)	cin >> b[i];
		ll res = 2e9;
		ll now = 0, have = 0;	//当前已经度过的天数和已经拥有的余额 
		
		for(int i = 1 ; i <= n ; i ++)
		{
			//在当前等级达成目的需要花费的天数 
			res = min(res, (c - have + a[i] - 1) / a[i] + now);	
			if(i < n)
			{
				//升级到下一级还需要工作多少天才够钱升级 
				int d = (b[i] - have + a[i] - 1) / a[i];
				have += d * a[i] - b[i];
				now += d + 1;				
			}
		}
		
		cout << res << endl;
    }
    return 0;
}

G题

这题建议直接看我的另一个题解:AcWing 1296. 聪明的燕姿
题意:让你找到一个最小正整数,使得它的所有约数之和为给定值\(c\).

思路:见上述另一个题解。
代码如下

int primes[N], cnt;
bool st[N];
int ans[N], len;
 
void get(int n)
{
    for(int i = 2 ; i <= n ; i ++)
    {
        if(!st[i]) primes[cnt ++] = i;
        for(int j = 0 ; primes[j] * i <= n ; j ++)
        {
            st[primes[j] * i] = true;
            if(i % primes[j] == 0) break;
        }
    }
}
 
bool judge(int x)
{
    if(x < N) return !st[x];
    for(int i = 2 ; i <= x / i ; i ++)
        if(x % i == 0) return false;
    return true;
}
 
void dfs(int last, int sum, int s)
{
    if(s == 1)
    {
        ans[len ++] = sum;
        return;
    }
    
    if(s - 1 > (last >= 0 ? primes[last] : 1) && judge(s - 1)) ans[len ++] = sum * (s - 1);
    
    for(int i = last + 1 ; primes[i] <= s / primes[i] ; i ++)
    {
        int p = primes[i];
        for(int j = 1 + p, t = p ; j <= s ; t *= p, j += t)
            if(s % j == 0)
                dfs(i, sum * t, s / j);
    }
}
 
int main()
{
    IOS;
    int T;
    get(N - 1);
    cin >> T;
    while(T --)
    {
        int x;
        cin >> x;
        len = 0;
        dfs(-1, 1, x);
        sort(ans, ans + len);
        if(!len) cout << -1 << endl;
        else cout << ans[0] << endl;
    }
    return 0;
}
posted @ 2021-04-11 00:59  beatlesss  阅读(336)  评论(0编辑  收藏  举报