Div3还是比较水的…都是基本都是思维题,只涉及到很少的算法.
A. Three Piles of Candies
叽里呱啦说了一大堆,其实就是让求三个数的平均值…
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int n;
ll a,b,c;
scanf("%d",&n);
while(n--)
{
scanf("%lld%lld%lld",&a,&b,&c);
ll d=a+b+c;
printf("%lld\n",d/2);
}
return 0;
}
B. Odd Sum Segments
题意就是给一串数字,随便划分k个区间,问每个小区间的和是否和为奇数,如果是奇数,就输出yes,然后每个区间的末位置,如果不是就输出no
这个题应该是一个数论的问题.做这个题之前首先得先想到一个问题,那就是只有奇数个奇数相加和才是奇数。就像(1+1+1),而偶数个奇数相加是偶数,而这一个偶数的个数并不影响结果,所以我们就直接考虑奇数的位置和个数就好.详情请见代码。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[222222];
int b[222222]; //用来标记存奇数所在的位置
ll q,n,k;
int main()
{
//ios::sync_with_stdio(false);
cin>>q;
while(q--)
{
ll x=0;
ll y=0;
//memset(b,0,sizeof b);
cin>>n>>k;
for(int i=0;i<n;i++)
b[i]=0;
//int f=0;
for(int i=0;i<n;i++)
{
scanf("%lld",&a[i]);
if(a[i]&1)
b[x++]=i;
}
if(x<k) //如果奇数个数小于区间数朱姐输出no
{
cout<<"NO"<<endl;
continue;
}
else
{
if((x-k+1)%2==0) //出现一个奇数划分一个区间,如果第k-1个区间有偶数个奇数,则肯定不满足,输出no
cout<<"NO"<<endl;
else //剩余的情况都是可以的,直接输出来就好,注意格式
{
cout<<"YES"<<endl;
int tt=0;
for(int i=0;i<x;i++)
{
if(tt!=k-1)
{
printf("%d ",b[i]+1);
//cout<<b[i]+1<<" ";
tt++;
}
else
{
cout<<n<<endl;
break;
}
}
}
}
}
return 0;
}
C. Robot Breakout
//题意就是给定坐标上的一堆机器人,然后他的有的有故障,不能向某个方向移动(后四个数,哪个为0就不能向哪边移动),问最后这些机器人能不能移动到一个点上。如果可以的话,就随便输出一个点。
思路:先把最开始的最大的面积的坐标标记出来,然后按照给定的移动方向缩小面积,最后随便输出一个边界点!
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
ios::sync_with_stdio(false);
int q; cin>>q;
int x,y,a,b,c,d;
while(q--)
{
int flag=1;
int n; cin>>n;
int xx1,xx2,xx3,xx4,yy1,yy2,yy3,yy4;
xx1=xx2=100000;
xx4=xx3=-100000;
yy1=yy4=100000;
yy2=yy3=-100000; //四个角的四个坐标
while(n--)
{
cin>>x>>y>>a>>b>>c>>d;
if(flag)
{
if(a==0) //代表不能向左移动,所以左边的边取最大的x,下边同理
{
xx3=max(xx3,x);
xx4=max(xx4,x);
}
if(b==0)
{
yy1=min(y,yy1);
yy4=min(y,yy4);
}
if(c==0)
{
xx1=min(x,xx1);
xx2=min(x,xx2);
}
if(d==0)
{
yy2=max(y,yy2);
yy3=max(y,yy3);
}
}
if(xx3>xx2||yy3>yy4)//移动后冲突了,则代表不行
flag=0;
}
if(flag)
cout<<1<<" "<<xx3<<" "<<yy3<<endl;
else
cout<<0<<endl;
}
return 0;
}
D1. RGB Substring (easy version)
思路:由于是easy,所以暴力所有情况肯定能过…
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,q,k;
char s[22222];
int p(int a)
{
int b=a+k-1;
int x=0;
int y=0;
int z=0;
for(int i=a;i<=b;i=i+3)
if(s[i]!='R')
x++;
for(int i=a+1;i<=b;i=i+3)
if(s[i]!='G')
x++;
for(int i=a+2;i<=b;i=i+3)
if(s[i]!='B')
x++;
for(int i=a;i<=b;i=i+3)
if(s[i]!='G')
y++;
for(int i=a+1;i<=b;i=i+3)
if(s[i]!='B')
y++;
for(int i=a+2;i<=b;i=i+3)
if(s[i]!='R')
y++;
for(int i=a;i<=b;i=i+3)
if(s[i]!='B')
z++;
for(int i=a+1;i<=b;i=i+3)
if(s[i]!='R')
z++;
for(int i=a+2;i<=b;i=i+3)
if(s[i]!='G')
z++;
return min(x,min(y,z));
}
int main()
{
ios::sync_with_stdio(false);
cin>>q;
while(q--)
{
int zz=0;
int xx=999999;
cin>>n>>k>>s+1;
for(int i=1;i<=n-k+1;i++)
{
int zz=p(i);
xx=min(xx,zz);
}
cout<<xx<<endl;
}
return 0;
}
D2. RGB Substring (hard version)
题意和上边的一模一样,但是这个是hard…所以不能暴力了。不过仔细考虑一下还是很简单的,就是一个前缀和的更新和处理…和暴力的思路还是很像的。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
char str[2222222];
char t[222222];
int a[222222],sum[222222];
int main()
{
ios::sync_with_stdio(false);
int q; cin>>q;
while(q--)
{
int ans=999999999;
int n,k;
cin>>n>>k>>str+1;
for(int i=1;i<=n+4;i=i+3) //把t数组都更新为RGBRGB.....
{
t[i]='R';
t[i+1]='G';
t[i+2]='B';
}
for(int j=1;j<=3;j++) //先从R,再从G,再从B依次统计
{
for(int i=1;i<=n;i++)
{
if(t[i+j-1]!=str[i])
a[i]=1;
else
a[i]=0;
}
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+a[i]; //求前缀和
for(int i=k;i<=n;i++) //统计区间从X->X+k总共更新了几次
ans=min(ans,sum[i]-sum[i-k]);
}
cout<<ans<<endl;
}
return 0;
}
E. Connected Component on a Chessboard
题意:就是给定一个好大的棋盘(这个棋盘是一黑一白相邻的)…然后问有没有一个连续的区域里面包含b个黑方块,w个白方块,有的话,随便输出这个区域的所有坐标,没有的话就输出NO。
思路:实在是没办法了,暴力了一下,没想到A了…就是,如果max(b,w)>min(b,w)*3+1,肯定没答案…
其余的情况都是有答案的,先先选一行,把min(b,w)*2全部输出,然后把剩下的一次放在这一行的上一行和下一行…详情请见代码…
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int b,w;
int main()
{
//ios::sync_with_stdio(false);
int q; scanf("%d",&q);
while(q--)
{
scanf("%d%d",&b,&w);
int aa=min(b,w);
int bb=max(b,w);
if(bb>aa*3+1)
{
printf("NO\n");
}
else
{
if(b==w)
{
printf("YES\n");
for(int i=1;i<=b+w;i++)
printf("1 %d\n",i);
}
else if(b<w) //白色的多,就得从白色的那个放起,(防止4白1黑这种)
{
printf("YES\n");
for(int i=2;i<=b*2+2;i++)
printf("4 %d\n",i); //随便选了第四行
w=w-b-1;
if(w) //白色有剩余就把它放在第三行
{
for(int i=3;i<=b*2+2;i=i+2)
{
printf("3 %d\n",i);
w--;
if(w==0)
break;
}
}
if(w) //还有剩余就放在第五行
{
for(int i=3;i<=b*2+2;i=i+2)
{
printf("5 %d\n",i);
w--; //放一颗剩余的白棋少一颗
if(w==0) //放完的话就跳出循环,不用再继续输出了
break;
}
}
}
else if(b>w) //与上边同理,同样要注意(4黑1白这种情况)
{
printf("YES\n");
for(int i=3;i<=w*2+3;i++)
printf("4 %d\n",i);
b=b-w-1;
if(b)
{
for(int i=4;i<=w*2+3;i=i+2)
{
printf("3 %d\n",i);
b--;
if(b==0)
break;
}
}
if(b)
{
for(int i=4;i<=w*2+3;i=i+2)
{
printf("5 %d\n",i);
b--;
if(b==0)
break;
}
}
}
}
}
return 0;
}
F. K-th Path
题意:给定一个无向图,求第K短路径的长度。
自己没想出来,看的网上的题解,只需要保留k条边,这样已经有了k个点对的距离小于排好序后第k条边的距离。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
struct edge
{
int from,to;
ll dis;
}Edge[maxn];
bool cmp(edge a,edge b)
{
return a.dis<b.dis;
}
vector<ll> vec;
ll a[805],s[805][805];
int len,n,m,k;
void floyd()
{
for(int k=1;k<=len;k++)
for(int i=1;i<=len;i++)
for(int j=1;j<=len;j++)
s[i][j]=min(s[i][j],s[i][k]+s[k][j]);
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=0;i<m;i++)
scanf("%d%d%lld",&Edge[i].from,&Edge[i].to,&Edge[i].dis);
sort(Edge,Edge+m,cmp); //把边从小到大排序
for(int i=0;i<k;i++)
{
a[len++]=Edge[i].from;
a[len++]=Edge[i].to;
}
sort(a,a+len);
len=unique(a,a+len)-a; //去重函数,建议去学,挺高大尚的,第二次用了
// for(int i=0;i<=len;i++)
// cout<<a[i]<<" ";
for(int i=1;i<=len;i++) //初始化另一幅图
for(int j=1;j<=len;j++)
s[i][j]=1e16;
int t1,t2;
for(int i=0;i<k;i++)
{
t1=upper_bound(a,a+len,Edge[i].from)-a; //建议去学这个真香函数,这里要注意,当大于范围内的数,就
t2=upper_bound(a,a+len,Edge[i].to)-a;//返回n+1的位置,刚好巧妙的利用了这点,这里的Edge是排好序的
//cout<<endl<<t1<<" "<<t2;
s[t1][t2]=s[t2][t1]=Edge[i].dis; //存图
}
floyd();
for(int i=1;i<=len;i++)
for(int j=i+1;j<=len;j++)
if(s[i][j]!=1e16)
vec.push_back(s[i][j]);
sort(vec.begin(),vec.end()); //排序输出第k小
printf("%lld\n",vec[k-1]);
return 0;
}