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题详细注释