Codeforces Round #719 (Div. 3) A-G题解 G题详细注释

Posted 尘封陌路

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #719 (Div. 3) A-G题解 G题详细注释相关的知识,希望对你有一定的参考价值。

题目链接:
https://codeforces.com/contest/1520

A. Do Not Be Distracted!


思路:
数据范围小,直接暴力。

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N=100;
typedef long long ll;
typedef pair<int,int> PII;
map<char,int> mp;
int main()
{
	int t;
	int n;
	string s;
	cin>>t;
	while(t--)
	{
		cin>>n;
		cin>>s;
		//	mp.clear();
	//	cout<<s<<endl;
		string t;
		int flag=1;
		for(int i=0;i<s.size();i++)
		{
			for(int j=i;j<s.size();j++)
			{
				if(s[j]!=s[i]&&s[j+1]==s[i])
				{
					flag=-1;
					break;
				}
			}
		}
		if(flag==-1) cout<<"NO"<<endl;
		else cout<<"YES"<<endl; 
	}
	return 0;
}

B. Ordinary Numbers


思路:
暴力打表,再把相同的数放在数组里面。查询即可。具体看代码。
把1到1e9 ,类似 11,22,33,这种数全部打出来,并且从小到大,给他们赋值。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5;
typedef long long ll;
typedef pair<int,int> PII;
map<long long,int> mp;
ll a[N];
ll b[N];
int main()
{

	int cnt=1;
		long long k=0;
	for(int i=0;i<=9;i++) //几个10  
	{
	//	k=0;
		for(int j=1;j<=9;j++)  // 从1到9 
		{
				k=0;
			for(int t=0;t<=i;t++)
			{
				k=k*10+j;
			}
			b[cnt]=k;
			mp[k]=cnt++;
		//	cout<<k<<endl;
		}
	}
	ll h;
	cin>>h;
	ll n;
	while(h--)
	{
		ll ans=0;
		scanf("%lld",&n); 
	//	printf("b[%d]===%d \\n",1,b[1]);
		for(int i=1;i<=cnt;i++)
		{
			if(b[i]>n) 
			{
				ans=b[i-1];break;
			}
			if(b[i]==n)
			{
				ans=b[i];break;
					}		
		}	
		cout<<mp[ans]<<"\\n";
	} 

	
	return 0;
	
}

C. Not Adjacent Matrix


思路:(贪心)
上下左右不能相差1。再考虑到输入为1的情况,那么先排奇数,再排奇数。
也是很暴力的做法。。。

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N=110;
typedef long long ll;
typedef pair<int,int> PII;
map<int,int> mp;
int a[N][N];
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n;
		memset(a,0,sizeof(a));
		if(n==2) 
		{
			cout<<"-1"<<endl;continue;
		}
		int cnt=1;
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				a[i][j]=cnt;
				cnt+=2;
				if(cnt>n*n) break; 
			}
			if(cnt>n*n) break; 
		}
		cnt=2;
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				if(a[i][j]==0)
				{
					a[i][j]=cnt;
					cnt+=2;
					if(cnt>n*n) break;
				}
			}
			if(cnt>n*n) break;
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				cout<<a[i][j]<<" ";
			}
			cout<<"\\n";
		}
		
		
	}
	return 0;
}

D. Same Differences

思路:
转换一下公式 ,用Map存a[i]-i,即可以存大数据也可以不用处理负数。
既然以成对出现,遍历的时候直接ans+(mp[a[i]-i]]-1) 就行了,然后再mp[a[i]-i]]-1。看到好多人用乘法/2什么的太麻烦了。。。

具体见代码:
AC代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
typedef long long ll;
typedef pair<int,int> PII;
map<ll,ll> mp;
ll a[N],b[N],c[N];
int t,n;
int main()
{
	cin>>t;
	while(t--)
	{
		mp.clear();
		cin>>n;
		for(int i=1;i<=n;i++) 
		{
			scanf("%lld",&a[i]);
		}
		ll ans=0;
		for(int i=1;i<=n;i++) 
		{
			ll k=a[i]-i;
		//	cout<<k<<" ";
			mp[k]++;
		}
	//	cout<<endl;
		for(int i=1;i<=n;i++)
		{
			ll res=a[i]-i;
			ans+=mp[res]-1;
			mp[res]--;
		} 
		cout<<ans<<endl;
	}
	return 0;
}

E. Arranging The Sheep(贪心)

思路:
贪心的思想

1.以中间的那个羊为中心来排队,即所有羊往中间那个羊靠过去。
2.考虑到偶数情况不知道取哪个。。。懒得讨论,那就两个都算一遍,取个min。

AC代码:

#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const int N=1e6+20;
typedef long long ll;
typedef pair<int,int> PII;
map<int,int> mp;
int b[N];
char a[N];

int main()
{
	IOS
	int t;
	cin>>t;
	int n;
	while(t--)
	{
		cin>>n;
		int cnt=0;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
			if(a[i]=='*')
			{
				b[++cnt]=i;
			}
		}
	//	for(int i=1;i<=cnt;i++) cout<<b[i]<<" ";
	//	cout<<endl;
		int k=b[cnt/2];
		int k2=b[cnt/2+1];
	//	printf("k===%d \\n",k);
		ll ans1=0;
		ll ans2=0;
		int res1=cnt/2;
		int res2=cnt/2+1;
		for(int i=res1-1;i>=1;i--)
		{
		//	printf("k-1===%d b[i]===%d \\n",k-1,b[i]);
			ans1+=abs(k-1-b[i]);
		//	printf("ans1===%d \\n",ans1);
			k--;
		}
		k=b[cnt/2];
		for(int i=res1+1;i<=cnt;i++)
		{
			ans1+=abs(b[i]-(k+1));
			k++;
		}
		//-------------------------------//
		
		//printf("k2==%d res2===%d \\n",k2,res2);
			for(int i=res2-1;i>=1;i--)
		{
		//	printf("k-1===%d b[i]===%d \\n",k-1,b[i]);
			ans2+=abs(k2-1-b[i]);
		//	printf("k2-1==%d b[i]==%d \\n",k2-1,b[i]);
		//	printf("ans2===%d \\n",ans2);
			k2--;
		}
		k2=b[cnt/2+1];
		for(int i=res2+1;i<=cnt;i++)
		{
			ans2+=abs(b[i]-(k2+1));
		//	printf("ans2===%d \\n",ans2);
			k2++;
		}
		cout<<min(ans1,ans2)<<endl;
	}
	return 0;
}

F1. Guess the K-th Zero (Easy version)(二分)


小总结:(交互题大多数情况)

1.二分

2.分块 分组

3.二进制思想

思路:
我们可以查询sum[L,R]的值,那么[L,R]区间内的0的个数就可以计算出来== (R-L+1)-sum[L,R]

假设: 如果我们要寻找第3个0 。
8-sum[1,8]=4 ([1,8]有4个0)
此时,我们缩小右边界
7-sum[1,7]=3 (有3个0)
再缩小
6-sum[1,6]=2 (有2个0)
可以发现: a[7]就等于0

再注意交互题的常见格式和套路,具体见代码:

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,k;
int query(int l,int r)
{
	cout<<"?"<<l<<" "<<r<<"\\n";
	fflush(stdout);
	int x;
	cin>>x;
	return x;
}
bool check(int cur)
{
	if(cur-query(1,cur)>=k) return 1;
	return 0;
}

int main()
{
	cin>>n>>k;cin>>k;
	int l=1,r=n;
	while(l<r)
	{
		int mid=(l+r)>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	if(check(l)) cout<<"! "<<l<<endl;
	else cout<<"! "<<r<<endl;
	return 0;
}

F2. Guess the K-th Zero (Hard version)(分组)

思路:(参考et3_tsy)

看数据范围
1.询问1e4

2.数组大小 2e5

2e5 :
[1,10] ,[11,20],[21,30]…10个数为一组,一共2e4

3.提问次数 6e4

2e4次机会,求出前i组有多少个0

注意: 要处理最后一组不满0的情况。

我们用一个save数组存:save[i] 为 前i组 的0的个数。
当我们回答的时候,就需要更新这个i后面的组。

注意组的边界的处理: 具体见代码:

#include<bits/stdc++.h>
#define rep(x,y,z) for(int x=y;x<=z;x++)
using namespace std;
const int N=2e5+10;
int n,k,t;
int save[N];//save[i] 表示,前i组,0的个数 
int cnt;
// #define mid ((l+r)>>1)

int query(int l,int r)
{
	cout<<"? "<<l<<" "<<r<<"\\n";
	fflush(stdout);
	int x;
	cin>>x;
	return x;
}

int ansr(int x)
{
	cout<<"! "<<x<<"\\n";
	fflush(stdout);
	for(int i=(x-1)/10+1;i<=cnt;i++) save[i]--;
	// 当前所在的组别到后面的组全部减1 
} 
bool check(int cur)
{
	if(cur-query(1,cur)>=k) return 1;
	return 0;
}

int main()
{
	cin>>n>>t;
	//cnt=(n-1+10)/10; //向上取整
	cnt=n/10;
	if(cnt*10<n) cnt++; 
	bool ok=0;
	while(t--)
	{
		cin>>k;
		if(!ok)
		{
			ok=1;
			for(int i=1;i<=cnt;i++)
			{
				save[i]=min(n,i*10)-query(1,min(n,i*10));//最多 2e4 
				
			}
			
		}
		int l=0,r=0;
		while(save[r]<k) r++;
		r=r*10,l=r-10,r=min(n,r);
		//l=1 r=2
		while(l+1<r)
		{
			int mid=(l+r)>>1;
			if(check(mid)) r=mid;
			else l=mid;	
		}	
		ansr(r);
	} 
	
	return 0;
}

G. To Go Or Not To Go?(详细注释)

思路:见代码注释。这题好像dijkstra…

AC代码:

#include<bits/stdc++.h>
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef pair<ll,PII> PIII;
const int N=2e3+10;const ll INF=0x3f3f3f3f3f3f3f3f;
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
int n,m,w;

int A[N][N],vis[N][N];// A存图,vis[i][j] 表示 A[i][j] 这个点是否走过 
ll d[N][N]; //表示从 (1,1)点到(i,j) 这个点的最短距离  
prio

以上是关于Codeforces Round #719 (Div. 3) A-G题解 G题详细注释的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #719 (Div. 3)Codeforces-1520ABCDE

Codeforces Round #719 (Div. 3) ABCDEF题解

Codeforces Round #719 (Div. 3) A-E

Codeforces Round #719 (Div. 3) A-G题解 G题详细注释

Codeforces Round #719 (Div. 3) A-G题解 G题详细注释

Codeforces Round #719 (Div. 3) A-G题解 G题详细注释