Codeforces Round #719 (Div. 3)题解A~G
A题
题意:给定一个字母串,问所有任意两个相同字母间是否有不同字符
遍历字符串 如果当前字母在前面出现了且和上一位不同 则一定有 ABA这种情况发生,输出NO即可
#include<iostream>
using namespace std;
int t,n;
char s[110];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
scanf("%s",s);
int a[27]={0};//a[i]=1表示'A'+i出现过 =0表示没出现
int f=0;
for(int i=0;i<n;i++)
{
if(!a[s[i]-'A'])//s[i]没出现过,标记s[i]
a[s[i]-'A']=1;
else
{
if(s[i]!=s[i-1])//s[i]在前面出现了且不是上一个,即不满足
f=1;
}
}
if(f==1)printf("NO\n");
else printf("YES\n");
}
}
B题
题意:1到n中满足数字的各位都相同的个数
分类讨论,1 11 111 1111…
2 22 222 2222 …
…
9 99 999 9999…
发现1e9内最多有9*10个 暴力即可
#include<iostream>
using namespace std;
long long t,n;
int main()
{
scanf("%lld",&t);
while(t--)
{
scanf("%lld",&n);
long long ans=0;//记录个数
for(long long i=1;i<=9;i++)
{
long long now=i;//计算i ii iii的个数
if(now<=n)ans++;
while(now*10+i<=n)
{// ii 变为iii 即x*10+i 3*10+3=33 33*10+3=333
now=now*10+i;
ans++;
}
}
printf("%lld\n",ans);
}
}
C题
题意:nn方格中填入1~nn,要求满足相邻格子的数不能相邻
构造方法如下
相邻的数都是斜着放的 所以满足条件,注意n=2 此时是特例没有方案可以满足
在这里插入代码片#include<iostream>
#include<algorithm>
using namespace std;
long long t,n;
int a[110][110];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
if(n==2)//特判
{
cout<<-1<<endl;
continue;
}
for(int i=1;i<=n;i++)
a[i][i]=i;//放对角线上的数
int idx=n+1;//放剩下的数
for(int i=2;i<=n;i++)
{
int x=1,y=i;
while(x<=n&&y>=1)
{
if(x==y)
{
x++;
y--;
continue;
}
a[x][y]=idx++;
x++;
y--;
}
}
for(int i=2;i<=n;i++)
{
int x=i,y=n;
while(x<=n&&y>=1)
{
if(x==y)
{
x++;
y--;
continue;
}
a[x][y]=idx++;
x++;
y--;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
printf("%d ",a[i][j]);
printf("\n");
}
}
}
D题
求满足aj-ai=j-i的组数,转换下 aj-j=ai-i,式子两边独立 每个ai-i即可再排序
#include<iostream>
#include<algorithm>
using namespace std;
long long t,n;
int a[200010];
int main()
{
scanf("%lld",&t);
while(t--)
{
scanf("%lld",&n);
long long ans=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i]-=i;
}
sort(a+1,a+1+n);//排序
long long now=0,x=a[1];
for(int i=1;i<=n;i++)
{
if(a[i]==x)
{
now++;
}
else
{
ans+=(now-1)*now/2;
x=a[i];
now=1;
}
}
ans+=(now-1)*now/2;
printf("%lld\n",ans);
}
}
E题
题意:一个字符串 *代表羊 。代表空地 要求所有羊要连在一起 求所有羊移动步数的最小值
很显然最终的羊会向中间靠拢所以
到羊的中位数的距离最短
序号 1 2 3 4 5 6 7 8 9 10
* . * . . . * . * *
看出羊的中位数为 7(共5只羊,第三只羊处的位子为中位数)
又因为不是每只羊都要到中位数,(中位数只能有一只羊)
故五只羊离中位数的距离分别为
2 1 0 1 2
就是上面的abs(k/2-i)
k/2是羊数的中位数 3
i是第几只羊
#include "stdio.h"
#include "math.h"
int a[1999999];
char b[1999999];
int main()
{
int m,j,k,l,i;
scanf("%d",&m);
while(m--)
{
k=1;
scanf("%lld",&l);
// getchar();
scanf("%s",b);
for(i=0;i<l;i++)
{
if(b[i]=='*')
a[k++]=i+1;
}
long long mid=a[(k/2)];
// printf("%d**\n",mid);
long long n=0;
for(i=1;i<k;i++)
{
n+=abs(mid-a[i])-abs(k/2-i);
}
printf("%lld\n",n);
}
}
F1题
常见交互题:有一个01序列,你可以询问l到r内1的个数 求第k个0的位置,二分即可
#include<iostream>
#include<math.h>
#include<string.h>
#include<algorithm>
using namespace std;
int n,t,k;
int a[10]={1,0,1,1,0,1};
int main()
{
cin>>n>>t;
cin>>k;
// 1 6 3 4 6 5 1 4 5 1
int now=0;
int l=1,r=n;
while(l<r)
{
int mid=l+r>>1;
cout<<"? "<<l<<' '<<mid<<endl;
fflush(stdout);
int x;
cin>>x;
if(now+mid-l+1-x>=k)r=mid;
else now=now+mid-l+1-x,l=mid+1;
}
cout<<"! "<<l<<endl;
}
F2题
多了个限制 每次查询后0变成1 还是二分 保证每次查询没有重复即可消除0变1的影响
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int sum[maxn];
int main(){
int t,k,l,r,n,mid,cnt,ans;
memset(sum,-1,sizeof(sum));
cin>>n>>t;
while(t--){
cin>>k;
l=1,r=n;
ans=0;
while(l<=r){
mid=(l+r)>>1;
if(sum[mid]==-1){
cout<<"? 1 "<<mid<<endl;
cin>>sum[mid];
}
int cnt0=mid-sum[mid];
if(cnt0>=k){
ans=mid;
r=mid-1;
}else l=mid+1;
}
cout<<"! "<<ans<<endl;
for(int i=ans;i<=n;i++)if(sum[i]!=-1)sum[i]++;
}
return 0;
}
G题
2200分的题 巧妙点在于最多只会传送一次 因为 假设A到B B到 C
ans=sum(1,A)+A+B+B+C+sum(C,n)不如直接A到C ans=sum(1,A)+A+C+sum(c,n)
所以只会传送一次或者不传送
1。不传送 bfs O(n)即可求出
2. 传送一次 ans=sum(1,A)+A+C+sum(c,n) 发现(sum(1,A)+A)+(C+sum(c,n))这两部分是独立的 所以可以从1 跑一遍最短路 从 n跑一遍最短路 两边各取最小值相加既是最小值
如果数据水一点的话可以考虑另一种做法 建立虚点 每个传送门和虚电连一条边跑dij也行
在这里插入代码片#include<iostream>
#include<queue>
using namespace std;
int n,m,w;
int a[2010][2110];
long long d[2010][2010];
long long d2[2010][2010];
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
queue<pair<int,int>>b,b2;
void bfs()
{
b.push({1,1});
d[1][1]=0;
while(b.size())
{
auto x=b.front();
b.pop();
for(int i=0;i<4;i++)
{
if(x.first+dx[i]>=1&&x.first+dx[i]<=n&&x.second+dy[i]>=1&&x.second+dy[i]<=m&&a[x.first+dx[i]][x.second+dy[i]]!=-1&&x.second+dy[i]>=1&&x.second+dy[i]<=m&&d[x.first+dx[i]][x.second+dy[i]]==1e18)
{
d[x.first+dx[i]][x.second+dy[i]]=d[x.first][x.second]+w;
b.push({x.first+dx[i],x.second+dy[i]});
}
}
}
}
void bfs2()
{
b2.push({n,m});
d2[n][m]=0;
while(b2.size())
{
auto x=b2.front();
b2.pop();
for(int i=0;i<4;i++)
{
if(x.first+dx[i]>=1&&x.first+dx[i]<=n&&x.second+dy[i]>=1&&x.second+dy[i]<=m&&a[x.first+dx[i]][x.second+dy[i]]!=-1&&d2[x.first+dx[i]][x.second+dy[i]]==1e18)
{
d2[x.first+dx[i]][x.second+dy[i]]=d2[x.first][x.second]+w;
b2.push({x.first+dx[i],x.second+dy[i]});
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&w);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]),d[i][j]=1e18,d2[i][j]=1e18;
bfs();
bfs2();
long long ans=1e18,xx=1e18,yy=1e18;
ans=min(ans,d[n][m]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(a[i][j]>0)
{
xx=min(xx,a[i][j]+d[i][j]);
yy=min(yy,a[i][j]+d2[i][j]);
}
}
ans=min(ans,xx+yy);
if(ans==1e18)cout<<-1<<endl;
else cout<<ans<<endl;
}