皮卡丘的梦想2
Problem Description
一天,一只住在 501 的皮卡丘决定发奋学习,成为像 LeiQ 一样的巨巨,于是他向镇上的贤者金桔请教如何才能进化成一只雷丘。
金桔告诉他需要进化石才能进化,并给了他一个地图,地图上有 n 个小镇,他需要从这些小镇中收集进化石。
接下来他会进行 q 次操作,可能是打听进化石的信息,也可能是向你询问 l 到 r 之间的进化石种类。
如果是打听信息,则皮卡丘会得到一个小镇的进化石变化信息,可能是引入了新的进化石,也可能是失去了全部的某种进化石。
如果是向你询问,你需要回答他第 l 个小镇到第 r 个小镇之间的进化石种类。
Input
首先输入一个整数 T (1 <= T <= 10),代表有 T 组数据。
每组数据的第一行输入一个整数 n (1 <= n <= 100000) 和一个整数 q (1 <= q <= 100000),分别代表有 n 个小镇,表皮卡丘有 q 次操作。
接下来输入 q 行,对于每次操作,先输入操作类型:
1: 紧接着输入 2 个整数 a(1 <= a <= n), b(1 <= b <= 60),表示第 a 个小镇引入了第 b 种进化石。
2: 紧接着输入 2 个整数 a(1 <= a <= n), b(1 <= b <= 60),表示第 a 个小镇失去了全部第 b 种进化石。
3: 紧接着输入 2 个整数 l, r (1 <= l <= r <= n),表示他想询问从第 l 个到第 r 个小镇上可收集的进化石有哪几种。
Output
对于每组输入,首先输出一行 "Case T:",表示当前是第几组数据。
每组数据中,对于每次操作 3,按编号升序输出所有可收集的进化石。如果没有进化石可收集,则输出一个小豪的百分号 "%"(不要问我为什么,出题就是这么任性)。
Example Input
1 10 10 3 1 10 1 1 50 3 1 5 1 2 20 3 1 1 3 1 2 2 1 50 2 2 20 3 1 2 3 1 10
Example Output
Case 1: % 50 50 20 50 % %
把每个小镇的有的进化石种类压缩成一个二进制数,然后就是一个裸的线段树了
也可以用60十个树状数组维护,更好写一些
#include<bits/stdc++.h>
using namespace std;
#define lson l,m,node<<1
#define rson m+1,r,node<<1|1
const int maxn=100005;
long long segtree[maxn*4];
void pushdown(int node)
{
segtree[node]=segtree[node<<1|1]|segtree[node<<1];
return ;
}
void update(int a,int b,int l,int r,int node)
{
if(l>=r)
{
segtree[node]|=(1ll<<b);
return ;
}
int m=(l+r)>>1;
if(a<=m)
{
update(a,b,lson);
}
else
update(a,b,rson);
pushdown(node);
}
void update2(int a,int b,int l,int r,int node)
{
if(l>=r)
{
segtree[node]&=(~(1ll<<b));
return ;
}
int m=(l+r)>>1;
if(a<=m)
{
update2(a,b,lson);
}
else
update2(a,b,rson);
pushdown(node);
}
long long query_find(int le,int ri,int l,int r,int node)
{
if(l>=le&&r<=ri)
{
return segtree[node];
}
if(l==r)
{
return segtree[node];
}
int m=(l+r)>>1;
long long ans=0;
if(m>=le)
{
ans|=query_find(le,ri,lson);
}
if(m<ri)
{
ans|=query_find(le,ri,rson);
}
return ans;
}
int main()
{
int flog,a,b,T,n,q;
long long i;
char mo='%';
cin>>T;
for(int j=1;j<=T;j++)
{
printf("Case %d:\n",j);
cin>>n>>q;
memset(segtree,0,sizeof(segtree));
while(q--)
{
scanf("%d %d %d",&flog,&a,&b);
if(flog==1)
{
update(a,b,1,n,1);
}
else if(flog==2)
{
update2(a,b,1,n,1);
}
else
{
long long ans=query_find(a,b,1,n,1);
int lala=0;
for(i=0;i<=62;i++)
{
if(ans&(1ll<<i))
{
if(lala)
printf(" ");
printf("%d",i);
lala=1;
}
}
if(!lala)
printf("%c",mo);
printf("\n");
}
}
}
return 0;
}
bLue的二叉树
Problem Description
Keke 是一个喜爱种树的人,他对各种树都有很深的研究。
MLE 听说 bLue 种了一些新品种的树,就想邀请 Keke 去围观一下。
PBH 在暗中把这一切尽收眼底,作为资深植树行家,他虽不屑,但也决定和他们一起去看一看。
于是,大家便一起到了 bLue 家去看树。
bLue 有两棵二叉树,分别有 n 和 m 个节点,编号分别为 1-n 和 1-m,每个节点都有一个权值,bLue 想知道第一棵树的所有子树中与第二棵树完全相同的个数(不考虑节点编号)。
Input
输入数据有多组(数据组数不超过 150),到 EOF 结束。
对于每组数据:
- 第一行有两个整数 n (0 < n <= 10^5) 和 m (0 < m <= 10^5),表示第一棵树和第二棵树的节点个数
- 接下来 n 行,表示第一棵树:第 i (0 < i <= n) 行有 3 个整数,w[i] (0 < w[i] <= 10), lc[i], rc[i] (0 < lc[i], rc[i] <= n),分别表示节点 i 的权值,该节点的左孩子编号和右孩子编号,若某个孩子不存在,则为 0 (数据保证每棵树都是合法的有根二叉树)
- 接下来 m 行,表示第二棵树:格式同第一棵树
保证:树的最大深度不会超过 10000。
Output
对于每组数据,输出一行一个整数 num,表示第一棵树的所有子树中与第二棵树完全相同的个数。
Example Input
7 4 1 6 3 2 0 4 1 7 0 3 0 0 1 2 1 2 0 0 2 0 0 2 0 0 1 4 0 1 1 2 2 0 0 3 3 1 0 0 2 1 3 3 0 0 1 0 3 2 1 0 3 0 0
Example Output
1 0
Hint
数据量比较大,推荐用 scanf 等读入。
题面kmp神暗示
#include<string.h>
#include<algorithm>
#include<string>
#include<stdio.h>
#include<iostream>
#include<stdlib.h>
using namespace std;
#define N 100010
char s[10*N], p[N];
int next1[N];
void get_next(char tem[])
{
int j = 0, k = -1;
int len = strlen(tem);
next1[0] = -1;
while (j<len)
{
if (k == -1 || tem[j] == tem[k])
next1[++j] = ++k;
else
k = next1[k];
}
}
int kmp(char *mat, char *pat)
{
int i = 0, j = 0, ans = 0;
int len = strlen(mat);
int len1 = strlen(pat);
get_next(pat); //printf("z\n");
while (i<len)
{
if (j == -1 || mat[i] == pat[j])
{
i++;
j++;
}
else
j = next1[j];
if (j == len1)//注意这个地方
{
ans++;
j = next1[j];
}
}
return ans;
}
struct nodd
{
int l, r, w;
}tree1[N], tree2[N];
int book[N];
int index1, index2;
int dfs1(int now)
{
if (tree1[now].w == 0)
{
s[index1++] = '#';
return 0;
}
s[index1++] = tree1[now].w + 'a';
dfs1(tree1[now].l);
dfs1(tree1[now].r);
return 0;
}
int dfs2(int now)
{
if (tree2[now].w == 0)
{
p[index2++] = '#';
return 0;
}
p[index2++] = tree2[now].w + 'a';
dfs2(tree2[now].l);
dfs2(tree2[now].r);
return 0;
}
int main()
{
int head1, head2, n, m, i, ans1;
while (cin >> n >> m)
{
memset(book, 0, sizeof(book));
for (i = 1; i <= n; i++)
{
scanf("%d %d %d", &tree1[i].w, &tree1[i].l, &tree1[i].r);
book[tree1[i].l] = book[tree1[i].r] = 1;
}
for (i = 1; i <= n; i++)
{
if (!book[i])
{
index1 = 0;
dfs1(i);
break;
}
}
memset(book, 0, sizeof(book));
for (i = 1; i <= m; i++)
{
scanf("%d %d %d", &tree2[i].w, &tree2[i].l, &tree2[i].r);
book[tree2[i].l] = book[tree2[i].r] = 1;
}
for (i = 1; i <= n; i++)
{
if (!book[i])
{
index2 = 0;
dfs2(i);
break;
}
}
s[index1] = 0;
p[index2] = 0;
// cout<<s<<endl<<p<<endl;
ans1 = kmp(s, p);
cout << ans1 << endl;
}
return 0;
}
校赛~校赛~
Problem Description
SDUT 的校赛是从 2009 年开始的,康纳每年看到比赛之后,往往就会喊一声 “ma ji ya ba ku nai + 年份的缩写”。比如说 2009 年就会说 “ma ji ya ba ku nai 9”。年份的缩写是一个字符串形式的,但是如果当前选择的字符串以前已经被用过,就会再向前继续取,比如说 2019 年的话康纳一开始会选择 9 但是 9 已经被用过了,所以就会向前多加一位缩写为 19,于是就会说 “ma ji ya ba ku nai 19”,2100 年的话 0 被使用过了康纳就会说 “ma ji ya ba ku nai 00”。2119 年的话 9, 19 都被使用过了,所以缩写便是 119。于是就会说 “ma ji ya ba ku nai 119”。然后现在告诉你康纳喊的话的内容,你需要告诉康纳现在是哪一年的校赛。
看她这么萌~你还不赶快告诉她么~
Input
输入数据有多组(数据组数不超过 3),到 EOF 结束。
对于每组数据:
- 首先输入一行 n (1 <= n <= 100000),表示康纳喊话的次数
- 接下来 n 行,每行一个字符串,代表康纳喊话的内容。保证其中缩写的年份的字符串内容长度不超过 9
Output
对于每组输入,输出 n 行,每行输出一个整数表示康纳喊话中年份缩写所代表的具体年份。
Example Input
5 ma ji ya ba ku nai 9 ma ji ya ba ku nai 19 ma ji ya ba ku nai 99 ma ji ya ba ku nai 00 ma ji ya ba ku nai 2017
Example Output
2009 2019 2099 2100 12017
刚看没太有直接的思路,就一直在搞二叉树那个,其实打表找规律。。。。。。
规律打出来还是不难找的,
前一段不好统计,直接map存一下,后面比较好统计
打表代码
#include<string.h>
#include<algorithm>
#include<string>
#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<map>
using namespace std;
string huan(int x)
{
string ch;
while (x)
{
ch += '0' + x % 10;
x /= 10;
}
return ch;
}
string ans[2000];
int main()
{
map<string, int>p;
int i, j;
int tt=0;
for (i = 2009; i <= 200000; i++)
{
string ch = huan(i);
string now;
for (j = 0; j < ch.size(); j++)
{
now += ch[j];
if (!p.count(now))
{
p[now] = 1;
if(now!=ch)
{
reverse(now.begin(), now.end());
tt++;
cout<<i<<" "<<now<<endl;
}
break;
}
}
if(tt%300==0)
system("pause");
}
return 0;
}
ac代码:
#include<bits/stdc++.h>
using namespace std;
string huan(int x)
{
string ch;
while (x)
{
ch += '0' + x % 10;
x /= 10;
}
return ch;
}
int main()
{
map<string, int>p;
map<string,string>pp;
int beginn = 2009;
int i, j;
string ch;
for (i = 2009; i <= 3118; i++)
{
ch = huan(i);
string now="";
for (j = 0; j < ch.size(); j++)
{
now += ch[j];
if (!p.count(now))
{
p[now] = 1;
if(now!=ch)
{
reverse(now.begin(), now.end());
reverse(ch.begin(), ch.end());
pp[now]=ch;
}
break;
}
}
}
string le[20];
le[0]="0000";
for(i=1;i<=10;i++)
le[i]=le[i-1]+'0';
string ri[20];
ri[0]="3118";
for(i=1;i<=10;i++)
ri[i]='1'+ri[i-1];
char tun[5];
int T;
while(cin>>T)
{
while(T--)
{
for(i=0;i<6;i++)
scanf("%s",tun);
cin>>ch;
int len=ch.size();
if(pp.count(ch))
cout<<pp[ch]<<endl;
else
{
if(ch<=ri[len-4]&&ch>=le[len-4])
{
printf("1");
cout<<ch<<endl;
}
else
cout<<ch<<endl;
}
}
}
return 0;
}