牛客练习赛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 }

posted @ 2018-11-12 20:29  霜雪千年  阅读(229)  评论(0编辑  收藏  举报