牛客练习赛30
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求每个节点到根节点的距离dist,dist为奇数的节点为cnt_1个,dist为偶数的节点为cnt_0个,这里设置根节点为0,那么构成三元组的个数为(cnt_0)3+(cnt_1)3。显然,三元组(i,j,k)对于距离为偶数的节点来说,i、j、k每个值都可以选择cnt_0个节点,即(cnt_0)3;对于距离为奇数来说,根据奇数+奇数=偶数,奇数-奇数=偶数可知,i、j、k每个值同样可以取cnt_1个节点,即(cnt_1)3,最终的答案就为(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 }