Codeforces Round #739 (Div. 3)

Codeforces Round #739 (Div. 3)

A. Dislike of Threes

题目大意:输出第\(k\)个不能被\(3\)整除且个位数不是\(3\)的数。

分析:暴力枚举,从\(1\)开始,判断每个数\(x\)是否\(x\%3\neq 0 且 x\%10\neq 3\)

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;

void read(int &sum)
{
	sum=0;char last='w',ch=getchar();
	while (ch<'0' || ch>'9') last=ch,ch=getchar();
	while (ch>='0' && ch<='9') sum=sum*10+ch-'0',ch=getchar();
	if (last=='-') sum=-sum;
}
int main()
{
//	freopen("M.in","r",stdin);
//	freopen("M.out","w",stdout);
	int len=0,a[10000],i=1;
	while (len<1000)
	{
		if (i%3!=0 && i%10!=3) a[++len]=i;
		i++; 
	}
	int t;
	read(t);
	while (t--)
	{
		int x;read(x);
		printf("%d\n",a[x]);
	}
//	fclose(stdin);fclose(stdout);
	return 0;
}

B. Who's Opposite?

题目大意:有\(n(2|n)\)个人围成一个圈,每个人编号分别为\(1,2,3...n\),第\(x\)个人正对面的人是第\(y\)个人,给出\(x,y\),问第\(z\)个人所对的人的编号是多少,无解输出\(-1\)

分析:

  1. 观察两个人何时能相对,设\(s_1\)\(x,y\)左边间隔的人,设\(s_2\)\(x,y\)右边间隔的人,发现当且仅当\(s_1=s_2\)时,\(x,y\)是相当的
  2. 所以令\(a=min(x,y),b=max(x,y)\),那么\(s_2=y-x-1\)\(s_1=s_2\),但明显\(s_1\)至少为\(1\)~\(x-1\)的人数,所以\(s_1\geqslant x-1\),如果\(s_2<x-1\)那么就是无解
  3. 通过\(s_1\),\(s_2\),容易求出\(n=s_1+s_2+2\),如果\(z>n\)也是无解
  4. 最后根据\(s_2\)可以得出于\(z\)相对的人的位置在\((z+s_2)\)的位置上,\(\%\)一下就好了

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;

void read(int &sum)
{
	sum=0;char last='w',ch=getchar();
	while (ch<'0' || ch>'9') last=ch,ch=getchar();
	while (ch>='0' && ch<='9') sum=sum*10+ch-'0',ch=getchar();
	if (last=='-') sum=-sum;
}
int t;
int a,b,c; 
int main()
{
//	freopen("M.in","r",stdin);
//	freopen("M.out","w",stdout);
	read(t);
	while (t--)
	{
		read(a),read(b),read(c);
		if (a>b) swap(a,b);
		if (a-1>b-a-1) { printf("-1\n"); continue; }
		int n=b+((b-a-1)-(a-1));
		if (c>n) { printf("-1\n"); continue; }
		if ((b+c-a+n*4)%n==0) printf("%d\n",n);
		else printf("%d\n",(b+c-a+n*4)%n);
		
	}
//	fclose(stdin);fclose(stdout);
	return 0;
}

C. Infinity Table

题目大意:按图的方式填格子,问\(x\)在那个格子?

在这里插入图片描述

分析:

  1. 发现填充的顺序是在这里插入图片描述的一个顺序
  2. 所以把其分成\(n\)段向下,和向左移动的子段,发现\((n,1)=k^2\),所以可以知道\((\sqrt x)^2=(x的上一个平方数)\),于是就得到了\(x\)是从\((\sqrt x,1)\)开始往下的\(x-\sqrt x ^2\)的数所填充的位置

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;

void read(int &sum)
{
	sum=0;char last='w',ch=getchar();
	while (ch<'0' || ch>'9') last=ch,ch=getchar();
	while (ch>='0' && ch<='9') sum=sum*10+ch-'0',ch=getchar();
	if (last=='-') sum=-sum;
}
int t,n;
int main()
{
//	freopen("M.in","r",stdin);
//	freopen("M.out","w",stdout);
	read(t);
	while (t--)
	{
		read(n);
		int k=sqrt(n)+1;
		if (n==(k-1)*(k-1)) k--;
		if (n-(k-1)*(k-1)<k) printf("%d %d\n",n-(k-1)*(k-1),k);
		else printf("%d %d\n",k,k-(n-(k-1)*(k-1)-k));
	}
//	fclose(stdin);fclose(stdout);
	return 0;
}

D. Make a Power of Two

题目大意:给出\(x\),每次可以删除\(x\)的任意一位,或在\(x\)末尾添一个数字,问使得\(x=2^k(k\geqslant 0)\)的最少次数

分析:

  1. 考虑极端情况,\(x\)\(9\)位,删\(9\)位在加上\(1\)\(2\),那\(x\)必然合法,所以最多操作\(10\)次,所以\(x\leqslant 10^{19}\),所以枚举\(k=1到63\),选取最小操作方案
  2. 这样,问题就变为了给两个数\(a,b\),问是的\(a\),变成\(b\)的最小操作次数,举个例子在这里插入图片描述\(1052\)变成\(1024\),因为我们是可以在末尾添加,而不能在首位添加,所以要使得高位相等的代价要高于使低位相等的代价,所以就要尽量使高位相等,从高位开始匹配即可,余下的位数要剪掉

代码:

在这里插入代码片#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
typedef long long ll;

void read(int &sum)
{
	sum=0;char last='w',ch=getchar();
	while (ch<'0' || ch>'9') last=ch,ch=getchar();
	while (ch>='0' && ch<='9') sum=sum*10+ch-'0',ch=getchar();
	if (last=='-') sum=-sum;
}
int t;
string n;
int sortm(int a,int b)
{
	if (b==0) return 1;
	if (b==1) return a;
	int t=sortm(a,b/2);
	if (b%2==1) return t*t*b;
	else return t*t;
}
int solve(string a,int m)
{
	string b;char f[100];int len=0;
	while (m!=0)
	{
		char ch=m%10+'0';m/=10;
		f[len]=ch;len++;
	}
	for (int i=len-1;i>=0;i--)
		b+=f[i];
//	cout << b  << " " << a << endl;
	int l=0,r=0;
	int sum=0;
//	printf("l,r : %d %d\n",l,r);
	while (l<a.length() && r<b.length())
	{
//		printf("%c %c\n",a[l],b[r]);
		if (a[l]==b[r]) l++,r++;
		else l++,sum++;
	}
//	cout << a << " " << b << endl;
	if (l!=a.length()) sum+=a.length()-1-l+1;
	if (r!=b.length()) sum+=b.length()-1-r+1;
	return sum;
}
signed main()
{
//	freopen("M.in","r",stdin);
//	freopen("M.out","w",stdout);
	read(t);
	while (t--)
	{
		cin >> n;
		int k=1,ans=1<<30;
		for (int i=0;i<=60;i++)
		{
			ans=min(ans,solve(n,k));
//			printf("%lld %lld\n",solve(n,k),k);
			k*=2;
		}
		printf("%lld\n",ans);
	}
//	fclose(stdin);fclose(stdout);
	return 0;
}

E. Polycarp and String Transformation

题目大意:原来有一串字符\(s\),每次删除其中一种字母,直到为空串,设每次删除后的字符串为\(s_1,s_2...s_k\),则字符串\(t=s+s_1+s_2+...+s_k\),现在给出\(t\),问原字符串\(s\)是啥,以及字母删除的顺序。

分析:

  1. 首先可以发现,如果在一个位置\(mid\)上,\(1\) ~ \(mid\)中字符\(G\)出现了,但在\(mid+1\) ~ \(t.length()\)中没有出现,则可以断定\(G\)被删除了,从开头枚举到结尾,就可以得到删除的顺序了
  2. 那么如何求出\(s\)呢?观察\(t\)的构成,\(t=s+s_1+s_2+...+s_k\),那么根据每个字母删除的顺序,我们可以得到,在\(t\)中,每个字母出现了\(S_{在s中出现的次数}*T_{第几个删除的}\),因为\(s\)\(t\)的开头,枚举结尾在哪,利用前缀和判断是否合法即可

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

int bz[26];
int* cnt=bz-'a';
pair<string,string> dep(string s)
{
	string ch;
	reverse(s.begin(), s.end());
	for (auto c:s)
	{
		if (!cnt[c])
			ch.push_back(c);
		cnt[c]++;
	}
	int m = ch.length();
	int yyds = 0;
	for (int i = 0; i < m; i++)
		yyds += cnt[ch[i]] / (m - i);

	reverse(ch.begin(), ch.end());
	return { string(s.rbegin(), s.rbegin() + yyds), ch };
}
string solve(pair<string, string> p)
{
	string result = p.first;

	for (auto c : p.second)
	{
		string temp;
		for (auto d : p.first)
			if (d != c)
			{
				temp.push_back(d);
				result.push_back(d);
			}
		p.first = temp;
	}

	return result;
}
int t;
int main()
{
	cin >> t;
	while (t--)
	{
		memset(bz,0,sizeof(bz));
		string s;
		cin >> s;
		auto ans=dep(s);
		auto check=solve(ans);
		if (check==s)
			cout << ans.first << ' ' << ans.second << '\n';
		else
			cout << "-1\n";
	}

	return 0;
}

F. Nearest Beautiful Number

题目大意:给出\(n\),求大于等于\(n\)且最多有\(k\)个不同数字的最小数

分析:

  1. 从高位开始考虑,设当为第\(i\)位,值为\(x\),记录答案数字第\(i\)位的数组为\(a\),分两种情况
  1. 如何\(a\)不足\(k\)位,直接\(a[i]=x\)
  2. 如果\(a\)已经有\(k\)位了,两种情况
  1. 如果当位的值\(x\)已经在\(a\)中出现过了,直接填\(a[i]=x\)即可
  2. 如果当前位的值\(x\)没有在\(a\)中出现,也分两种情况
  1. 如果前面的值是大于\(n\)的前\(i-1\)位的,那么就可以填一个前面最小的数
  2. 如果前面的值是等于\(n\)的前\(i-1\)位的,分类
  1. 尝试修改从前面已经出现过的数字中,选一个\(\geqslant x\)且最小的数
  2. 在第一种失败的情况下,就考虑把\(a[1]\)$a[i-1]$中的某个数字变大,然后这一位在填$a[1]$\(a[i-1]\)中最小的数

代码

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

string solve()
{
	string n;
	int k;
	cin >> n >> k;
	while (true)
	{
		set<char> s;
		for (auto c : n) s.insert(c);
		if (s.size() <= k) return n;
		s.clear();
		int ptr = 0;
		while (ptr++)
		{
			s.insert(n[ptr]);
			if (s.size()>k)
			{
				while (n[ptr]=='9') ptr--;
				n[ptr]++;
				for (int i=ptr+1;i<n.size();i++)
					n[i]='0';
				break;
			}
		}
	}
}
int t;
int main()
{
	cin >> t;
	while (t--)
		cout << solve() << '\n';
	return 0;
}
posted @ 2021-10-17 10:36  WBWYX  阅读(33)  评论(0)    收藏  举报