A - Kefa and Park
題目鏈接:http://codeforces.com/problemset/problem/580/C
題目大意:kefa住在編號爲1的房子裏,現在kefa要去餐廳,餐廳位於樹的葉子節點,現在給一個m,如果kefa去餐廳的路徑連續遇到貓的個數大於m,該餐廳kefa就不會過去,1位置上有貓。問kefa可以去的餐廳個數。
解題思路:用dfs將圖跑一遍即可,過程中標記連續遇到貓的個數,還有一個點就是需要判斷該點是否爲葉子節點。最好不要用鏈式前向星,該方法判斷葉子節點不好判斷。
Code:
#include<iostream>
#include<vector>
using namespace std;
const int N = 1e6+5;
vector<int>ve[N];
int n,m,st[N],ans;
void dfs(int u,int k,int pr){//分別表示當前節點,連續貓的個數,父親節點
if(k>m) return ;
int num=ve[u].size();
if(num==1&&u!=1){
ans++;
return ;
}
for(int i=0;i<num;i++){
int v=ve[u][i];
if(v==pr) continue;
if(st[v]) dfs(v,k+1,u);
else dfs(v,0,u);
}
}
int main(){
ans=0;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>st[i];
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
ve[u].push_back(v);
ve[v].push_back(u);
}
dfs(1,st[1],0);
cout<<ans<<endl;
return 0;
}
B - Complete Tripartite
題目鏈接:http://codeforces.com/problemset/problem/1228/D
題目大意:問能否將一個圖分成三個集合,每個集合內部的點沒有邊,每個集合的點都和另外兩個集合的點連有邊,每個集合不能爲空。
解題思路:先將1放在集合1,然後將和1相連的點全部置爲2,剩下的點自然就是集合1裏面的元素,然後再從集合2中隨意找一個元素,遍歷和它相連的點,如果該點不屬於集合1,就將該點放在集合3中。這樣就將三個集合找出來了。最後判斷三個集合是否與題意有衝突即可。
Code:
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
const int N = 6e5+5,M=N*2;
typedef long long ll;
ll h[N],cnt;
ll n,m,color[N],in[N];
vector<ll>v[4];
struct Edges{
ll to,nxt;
}eg[M];
void add(ll u,ll v){
eg[cnt].to=v;
eg[cnt].nxt=h[u];
h[u]=cnt++;
}
int main(){
memset(h,-1,sizeof(h));
cnt=0;
cin>>n>>m;
for(ll i=0;i<m;i++){
ll u,v;
cin>>u>>v;
in[u]++;in[v]++;//表示每個點和多少邊相連
add(u,v);add(v,u);
}
// cout<<"***********"<<endl;
color[1]=1;
for(ll i=h[1];i!=-1;i=eg[i].nxt){//先把和1相連的邊的點都置爲2
ll v=eg[i].to;
color[v]=2;
}
ll pos=-1;
for(ll i=1;i<=n;i++){//剩下的點的顏色都置爲1
if(color[i]!=2) color[i]=1;
else if(pos==-1){
pos=i;
}
}
if(pos==-1){
cout<<-1<<endl;
return 0;
}
for(ll i=h[pos];i!=-1;i=eg[i].nxt){//和顏色爲2的點相連的點顏色不爲1就一定爲3
ll v=eg[i].to;
if(color[v]==1) continue;
color[v]=3;
}
ll len1,len2,len3;
for(ll i=1;i<=n;i++){
if(color[i]==1) v[1].push_back(i);
else if(color[i]==2) v[2].push_back(i);
else v[3].push_back(i);
}
bool flag=0;
len1=v[1].size();len2=v[2].size();len3=v[3].size();
// cout<<"*************\n";
if(len1==0||len2==0||len3==0){//判斷是否有集合爲空
cout<<-1<<endl;
return 0;
}
for(ll i=0;i<len1;i++){
if(in[v[1][i]]!=len2+len3){//如果沒有和集合2,3所有的點相連,就不符合條件
flag=1;
break;
}
for(int j=h[v[1][i]];j!=-1;j=eg[j].nxt){//如果集合內部存在邊,不符合條件
int v=eg[j].to;
if(color[v]==1) {
flag=1;
break;
}
}
}
// cout<<"*************\n";
// cout<<len2<<endl;
// for(int i=1;i<=n;i++){
// cout<<h[i]<<endl;
// }
for(ll i=0;i<len2;i++){
if(in[v[2][i]]!=len1+len3){
flag=1;
break;
}
for(int j=h[v[2][i]];j!=-1;j=eg[j].nxt){
int v=eg[j].to;
if(color[v]==2) {
flag=1;
break;
}
// cout<<j<<endl;
}
}
// cout<<"*************\n";
if(flag){
cout<<-1<<endl;
return 0;
}
for(ll i=0;i<len3;i++){
if(in[v[3][i]]!=len1+len2){
flag=1;
break;
}
for(int j=h[v[3][i]];j!=-1;j=eg[j].nxt){
int v=eg[j].to;
if(color[v]==3) {
flag=1;
break;
}
}
}
// cout<<"*************\n";
if(flag){
cout<<-1<<endl;
return 0;
}
else {
for(ll i=1;i<=n;i++){
if(i==1) cout<<color[i];
else cout<<" "<<color[i];
}
cout<<endl;
}
return 0;
}
C - Shortest Cycle
題目鏈接:http://codeforces.com/problemset/problem/1206/D
題目大意:兩個數與運算不爲0,那麼就存在一條邊,判斷該圖中是否存在有環,存在輸出最小環的長度,反之輸出-1
解題思路:根據抽屜原理,若n大於128,則最小環一定爲3,反之跑floyd求最小環即可。
Code:
#include<iostream>
using namespace std;
const int N = 1e5+5;
typedef long long ll;
const ll inf = 1e14;
ll a[N],dis[300][300],e[300][300];
int n;
ll floyd(){
ll res=inf;
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j||i==k||j==k) continue;
res=min(res,dis[i][j]+e[j][k]+e[k][i]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
return res==inf?-1:res;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]==0){
i--;
n--;
}
}
if(n>128){
cout<<3<<endl;
}
else {
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(a[i]&a[j] && i!=j){
dis[i][j]=e[i][j]=1;
}
else {
dis[i][j]=e[i][j]=inf;
}
}
}
cout<<floyd()<<endl;
}
return 0;
}
D - Alex and a Rhombus
題目鏈接:http://codeforces.com/problemset/problem/1180/A
題目大意:思維題,根據圖中規律,給出第n次操作圖中小正方形的個數
解題思路:手動模擬可以得出,sn=n*(n-1)*2+1.
Code:
#include<iostream>
using namespace std;
int main(){
int n;
cin>>n;
cout<<n*(n-1)*2+1<<endl;
return 0;
}
E - Nick and Array
題目鏈接:http://codeforces.com/problemset/problem/1180/B
題目大意: 給你一個數組,每次操作形式爲在數組中任意挑選幾個數,每個數轉換形式爲ai=-ai-1;問怎樣轉換,使數組乘積最大。每個數都可多次操作。
解題思路:對於正數和0,轉化爲負數絕對值大於本身,明白這個後就簡單了。
如果數組元素個數爲偶數,全部轉化爲負數即可。
如果數組元素個數爲奇數,將所有元素轉化爲負數後,將絕對值最大的再進行一次操作即可
Code:
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e6+5;
int a[N],b[N],c[N],n,num1,num2,num3;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
int minn=0,temp;
if(n%2==0){
for(int i=1;i<=n;i++){
if(a[i]>=0) a[i]=-a[i]-1;
}
}
else if(n&1){
for(int i=1;i<=n;i++){
if(a[i]>=0) a[i]=-a[i]-1;
if(a[i]<minn) {
minn=a[i];
temp=i;
}
}
a[temp]=-a[temp]-1;
}
for(int i=1;i<=n;i++){
if(i==1) cout<<a[i];
else cout<<" "<<a[i];
}
cout<<endl;
return 0;}
F - Valeriy and Deque
題目鏈接:http://codeforces.com/problemset/problem/1180/C
題目大意:每次操作將數組頭兩個數取出,然後將值大的放入數組頭,值小的放在數組尾,問每次操作所取出來的兩個數分別是多少。
解題思路:用到一種新函數,deque,雙向隊列,和隊列操作差不多,多了從隊頭隊尾取出加入元素的操作。找到數組中最大數後找循環節,對循環之前和進入循環後分別處理即可。另外這題也可以暴力寫,畢竟有6s,每次都有這種大佬,暴力大法,無所不A。
Code:
#include<iostream>
#include<deque>
using namespace std;
const int N = 3e5+5;
typedef long long ll;
int n,m,maxx=0,num=0,ans[N];
deque<ll>q;
struct node {
int l,r;
}t[N];
void solve(){
while(1){
int x=q.front();q.pop_front();
int y=q.front();q.pop_front();
if(x==maxx){
q.push_front(y);
for(int i=1;i<=n-1;i++){
y=q.front();q.pop_front();
ans[i]=y;
}
break;
}
else {
num++;
t[num].l=x;t[num].r=y;
if(x>y){
q.push_front(x);
q.push_back(y);
}
else {
q.push_front(y);
q.push_back(x);
}
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) {
int x;
cin>>x;
maxx=max(maxx,x);
q.push_back(x);
}
solve();
for(int i=0;i<m;i++){
ll c;
cin>>c;
if(c<=num) cout<<t[c].l<<" "<<t[c].r<<endl;
else {
c-=num;
c%=(n-1);
if(c==0) c=n-1;//如若剛好乘除,此時c爲循環節最後一個元素
cout<<maxx<<" "<<ans[c]<<endl;
}
}
return 0;
}
G - Circle Metro
題目鏈接:http://codeforces.com/problemset/problem/1169/A
題目大意:A,B坐兩個列車坐到某個目標位置,列車循環轉,問A,B在下車之前是否會出現在同一個站點
解題思路:sb題,枚舉即可
Code:
#include<iostream>
using namespace std;
int n,a,x,b,y;
int main(){
cin>>n>>a>>x>>b>>y;
bool flag=0;
if(a==b){
flag=1;
}
while(a!=x&&b!=y){
a=a+1;b=b-1;
if(a==n+1) a=1;
if(b==0) b=n;
if(a==b){
flag=1;
break;
}
}
if(flag) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
return 0;
}
H - Pairs
題目鏈接:http://codeforces.com/problemset/problem/1169/B
題目大意:找到兩個數x,y;在給出的數組中至少有一個數和x或y相等。
解題思路:在第一行的兩個數一個數爲x,在剩下的裏面找y。看是否滿足條件。
Code:
#include<iostream>
#include<map>
using namespace std;
const int N = 3e5+5;
typedef long long ll;
ll n,m;
struct node {
ll x,y;
}num[N];
map<ll,ll>ma1,ma2;
ll x1,x2,sum1,sum2,x,y;
int main(){
sum1=1;sum2=1;
cin>>n>>m;
cin>>x1>>x2;
for(ll i=2;i<=m;i++) {
cin>>x>>y;
if(x!=x1&&y!=x1){
ma1[x]++;
ma1[y]++;
}
else sum1++;
if(x!=x2&&y!=x2){
ma2[x]++;
ma2[y]++;
}
else sum2++;
}
// cout<<sum1<<endl
bool flag=0;
for(int i=1;i<=n;i++){
if(i!=x1){
if(sum1+ma1[i]>=m){
cout<<"YES"<<endl;
flag=1;
break;
}
}
if(i!=x2){
if(sum2+ma2[i]>=m){
cout<<"YES"<<endl;
flag=1;break;
}
}
}
// cout<<"***********\n";
if(!flag) cout<<"NO"<<endl;
return 0;
}
I - Increasing by Modulo
題目鏈接:http://codeforces.com/problemset/problem/1169/C
題目大意:將一個數組變爲非遞減序列問最少操作次數
解題思路:二分操作次數求最小,先將last值設爲0,遍歷一遍數組,如果a[i]大於last,看在當前操作次數下是否可以將a[i]轉化爲last,如果不能則更新last=a[i],如果a[i]小於last,看在當前操作次數下將a[i]變得大於等於last,不行則說明當前情況不成立。
Code:
#include<iostream>
using namespace std;
const int N = 3e5+5;
int n,m,a[N];
bool check(int x){
int now=0;
for(int i=1;i<=n;i++){
if(now<a[i]){
if(m-a[i]+now>x) now=a[i];
}
else if(now>a[i]){
if(a[i]+x<now) return 0;
}
}
return 1;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
int l=0,r=1e9,mid,ans=1e9;
while(l<r){
mid = (l+r)>>1;
if(check(mid)){
r=mid;
ans=min(ans,mid);
}
else l=mid+1;
}
cout<<ans<<endl;
return 0;
}