1. 程式人生 > >牛客練習賽30

牛客練習賽30

clu using subject 爆炸 簡單 節點 根節點 can printf

A.回文日期

題目描述

眾所周知,小K是nowcoder的暴政茍管理,所以小K很擅長踢樹,雖然本題與踢樹無關 小K喜歡將日期排列成yyyy-mm-dd的形式(位數不足添零補齊)的形式,雖然這與小K只會做回文字符串這道水題無關,但小K覺得日期組成的回文串也是挺可愛的。作為一個涼心出題人,小K決定給你一個可愛的問題:給你兩個日期,求這兩個日期的閉區間內有多少個回文的日期(輸入可能包含多組數據)

輸入描述:

第一行包含一個整數T,表示有T組數據
接下來T行,每行兩個“yyyy-mm-dd"形式的日期

輸出描述:

輸出共T行,每行輸出當前數據的回文日期的個數
示例1

輸入

1
1926-08-16
2333-12-21

輸出

36

備註:

對於100%的數據,1 ≤ ?? ≤ 10,且日期的形式一定是 YYYY-MM-DD,且輸 入日期一定合法,保證答案的年份不會超過4位
解題思路:先簡單預處理一下回文日期,由於最多只有8位數,因此果斷將回文日期變成整數,同時特判一個特殊的閏年月份日期:92200229,然後暴力統計區間中的個數即可。
AC代碼:
 1 #include <bits/stdc++.h>
 2
using namespace std; 3 int T,y_1,m1,d1,y_2,m2,d2,tp1,tp2,ans,pos,now[500]; 4 int main(){ 5 memset(now,0,sizeof(now));pos=0,now[pos++]=92200229; 6 int dy[]={31,28,31,30,31,30,31,31,30,31,30,31}; 7 for(int i=1;i<=12;++i)//預處理 8 for(int j=1;j<=dy[i-1];++j) 9 now[pos++]=j%10
*10000000+j/10*1000000+i%10*100000+i/10*10000+i*100+dy[i-1]; 10 while(cin>>T){ 11 while(T--){ 12 scanf("%d-%d-%d",&y_1,&m1,&d1); 13 scanf("%d-%d-%d",&y_2,&m2,&d2); 14 ans=0; 15 tp1=y_1*10000+m1*100+d1,tp2=y_2*10000+m2*100+d2; 16 for(int i=0;i<pos;++i) 17 if(now[i]>=tp1&&now[i]<=tp2)ans++; 18 cout<<ans<<endl; 19 } 20 } 21 return 0; 22 }

C.小K的疑惑

題目描述

眾所周知,小K是一只連NOIP2018初賽都沒有過的蒟蒻,所以小K很擅長dfs序+分塊樹,但是本題與dfs序+分塊樹無關。

小K現在心態爆炸了,因為小K被一道簡單的數據結構題給卡住了,希望請你來解決它,但是小K又不想太麻煩你,於是將題面進行了簡化(其實是出題人懶得寫題面了233333)

Bob有??個點的樹,每條邊的長度有一個邊權,現在定義??????(??,??)代表第??個點到第??個點的距離模2之後的結果。問有多少(??,??,??)滿足,??????(??,??) = ??????(??,??) = ??????(??,??)。

輸入描述:

第一行一個整數??代表點的數量。
接下來?? − 1行每行三個數??,??,??代表有一條在??,??之間長度為??的邊。

輸出描述:

一行一個整數代表有多少對(??,??,??)滿足條件。
示例1

輸入

3
1 2 3
1 3 4

輸出

9

備註:

對於100%的數據,1 ≤ ?? ≤ 10000,0 ≤ ?? ≤ 233。
解題思路:任意兩點間的距離模2之後要麽是0要麽是1,通過畫圖分析可知,三元組(i,j,k)之間任意兩點之間的距離只能是偶數,只要參合一個距離為奇數的邊權都不可能構成三元組。於是問題就轉化成dfs求每個節點的深度,假設根節點為0,則每個節點到根節點的距離為奇數的個數為cnt_1,距離為偶數的個數為cnt_0,那麽構成三元組的個數為(cnt_0)3+(cnt_1)3
AC代碼:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const int maxn=10005;
 5 int n,cnt,x,y,z,head[maxn];LL cnt_0,cnt_1;
 6 struct node{int w,to,next;}edge[maxn<<1];///雙向邊
 7 void init(){memset(head,-1,sizeof(head));cnt=0;cnt_0=cnt_1=0;}
 8 LL pow_3(LL g){return g*g*g;}
 9 void add_edge(int u,int v,int val){
10     edge[cnt].w=val;
11     edge[cnt].to=v;
12     edge[cnt].next=head[u];///第cnt條邊記錄上一次起點為u的邊的編號
13     head[u]=cnt++;///head[u]表示當前以u為起點的第cnt條邊
14 }
15 void dfs(int cur,int pre,int val){
16     val&1?cnt_1++:cnt_0++;
17     for(int i=head[cur];~i;i=edge[i].next){
18         int v=edge[i].to;
19         int w=edge[i].w;
20         if(v^pre)dfs(v,cur,val+w);///防止進入死循環(建雙向邊)
21     }
22 }
23 int main(){
24     while(cin>>n){
25         init();
26         while(--n){
27             scanf("%d%d%d",&x,&y,&z);
28             add_edge(x,y,z);
29             add_edge(y,x,z);
30         }
31         dfs(1,0,0);///虛擬一個根節點0
32         printf("%lld\n",pow_3(cnt_0)+pow_3(cnt_1));
33     }
34     return 0;
35 }


牛客練習賽30