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;
}