头更更大
这个10月完就要去搞NOIP了。。。
10月30天也就3次测试。。。为保佑进省一我还是每次测试玩都写个总结。。
boomshakalaka。。。又又又全部写炸。。。
本来是可以AK的。。。。。。
第一题没有判0(虽然我以为我判了)
第二题情况没讨论完爆0
第三题first[i]数组都清零了cnt没清零
。。。。。。然后成外最低都105.。。。。。
LSW甚至AK。。。。。。
还说他们更做难题。。。。。。
。。。。。。希望没有北清班那些人。。。尤其是MRF和ZYY。。。
革命尚未成功。。。同志仍需努力。。。。
(把冰箱里那块冻过的面包拿过来)
下面面详细解答:
T1(35/100):
神秘代码:2001
problem
问你一些数能否被拆成两个斐波那契数的乘积。。
solution
凯爷说本来没有设定35%的线的。。。。
然后所有35%的人几乎都是忘了判0。。。
包括我。。。。。。
看起来唬人但是斐波那契数列是一个增长速度堪比2^n的东西。
所以说只需要在前46个斐波那契数中枚举就行了。。。。。。
T2(0/100):
神秘代码:2002
problem
问你一棵树(边权都是1)上距离指定两点的距离一样的点有多少个。
solution
这道题都会打但是情况不好判断。
预处理每个点所在的子树的点的数量。
首先通过LCA求出两点间最短距离dis。
然后判断dis是否是偶数。不是就输出0。
然后判断LCA是不是所求点之一。如果是,答案是所有的点的个数减去LCA两边的树的点集个数。
如果不是,直接利用预处理用倍增法找出中点再计算。
额。。详见代码吧。
T3(65/100):
神秘代码:2003
problem
问你在树(边权为1)上选择一些点,每个两点至少有一条线段相连,求需要的最少线段数。
solution
睡着睡着我竟然打出了标答树形dp。。。(虽然貌似贪心做的更简单一点)
然而没有把cnt清零Runtime Error了。。。。。。GG。。。。。。
感想
审题啊MMP!!!MMP!!!!!!
代码+题目
T1
Fibonacci
题目描述
豆豆最近迷上了 Fibonacci 数,然后他开始研究 Fibonacci 数的乘积。现在他想问你某个数能不能分解成两个 Fibonacci 数的乘积?
Fibonacci 数的定义:F0=0,F1=1,Fk=Fk-1+Fk-2 。
输入格式
第一行一个整数 T 代表提问次数。
接下来 T 行,每行一个数字 A 表示豆豆询问你的数。
输出格式
对于每次提问,如果这个数可以被分解成两个 Fibonacci 数的成绩输出“Yes”,否则输出“No”。
样例数据 1
输入 [复制]
5
5
4
12
11
10
输出
Yes
Yes
No
No
Yes
备注
【数据范围】
对于 50% 的数据:A≤50;
对于 100% 的数据:T≤100;0≤A≤109 。
my/std.cpp
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
inline int read()
{
int X=0,w=1; char ch=0;
while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
return X*w;
}
inline void write(int x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
int cnt,f[100500];
int initi()
{
f[0]=0;f[1]=1;
for(cnt=2;f[cnt-1]<1005000000;cnt++)
{
f[cnt]=f[cnt-1]+f[cnt-2];
//cout<<f[cnt]<<endl;
}
cnt-=1;
}
int t,x;
int main()
{
memset(f,0,sizeof(f));
initi();
//cout<<cnt<<endl;
t=read();
while(t--)
{
int flag=1;
x=read();
for(int i=0;i<=cnt;i++)
{
for(int j=0;j<=cnt;j++)
if(f[i]*f[j]==x)
{
flag=0;
cout<<"Yes"<<endl;
break;
}
if(!flag)break;
}
if(flag)cout<<"No"<<endl;
}
return 0;
}
T2
一样远
题目描述
企鹅国的城市结构是一棵树,有 N 座城市和 N-1 条无向道路,每条道路都一样长。豆豆和豆沙准备去参加 NOIP(National Olympiad in Informatics for Penguin),但是他们住在不同的地方,豆豆住在城市 A ,豆沙住在城市 B 。他们想找一个距离 A 和 B 一样远的集合地点,所以他们想知道有多少个城市满足这个要求?
由于他们会参加很多次 NOIP ,所以有很多个询问。
输入格式
第一行一个整数 N,代表城市个数。
接下来 N-1 行,每行两个数字 F 和 T ,表示城市 F 和城市 T 之间有一条道路。
接下来一行一个整数 M 代表询问次数。
接下来 M 行,每行两个数字 A 和 B ,表示这次询问的城市 A 和城市 B(A可能与B相同)。
输出格式
输出 M 行,每行一个整数表示到 A 和 B 一样远的城市个数。
样例数据 1
输入 [复制]
4
1 2
2 3
2 4
2
1 2
1 3
输出
0
2
样例数据 2
输入 [复制]
4
1 2
2 3
2 4
2
1 1
3 3
输出
4
4
备注
【数据范围】
对于 30% 的数据:N,M≤1000;
对于另外 10% 的数据:A=B;
对于另外 30% 的数据:保证树的形态随机;
对于 100% 的数据:1≤N,M≤100000。
my/std.cpp
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
inline int read()
{
int X=0,w=1; char ch=0;
while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
return X*w;
}
int n,m,x,y,z,u,v;
struct node{
int u,v,val,next;
}side[200010];
int cnt=0,first[100010];
void addedge(int u,int v,int val)
{
cnt += 1;
side[cnt].u = u;
side[cnt].v = v;
side[cnt].val = val;
side[cnt].next = first[u];
first[u] = cnt;
}
bool visit[100010];
int dep[100010],num[100010];
int f[100010][20];
int dfs(int root)
{
visit[root] = true;
for(int i=first[root];i;i=side[i].next)
{
int u = side[i].u; int v = side[i].v;
if(!visit[v])
{
f[v][0] = u;
dep[v] = dep[u] + 1;
num[root] += dfs(v);
}
}
return num[root];
}
#define maxx 100005
void initi(int root)
{
memset(dep,0,sizeof(dep));
dep[root] = 0;
num[root] = dfs(root);
for(int i=1;i<=18;i++)
for(int j=1;j<=maxx;j++)
if(f[j][i-1])
f[j][i] = f[f[j][i-1]][i-1];
}
int lca(int x,int y)
{
if(dep[x]<dep[y]){int k=x;x=y;y=k;}
int foot = dep[x] - dep[y];
for(int i=18;i>=0;i--)
if(foot>=(1<<i)) foot -= (1<<i),x=f[x][i];
if(x==y) return x;
for(int i=18;i>=0;i--)
if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
int main()
{
// freopen("equal.in","r",stdin);
// freopen("equal.out","w",stdout);
n=read();
for(int i=1;i<n;i++)
{
num[i]=1;
u=read(); v=read();
addedge(u,v,1);
addedge(v,u,1);
}num[n]=1;
initi(1);
m=read();
for(int i=1;i<=m;i++)
{
x=read(); y=read(); z=lca(x,y);
if(x==y){cout<<num[1]<<endl;continue;}
if((dep[x]+dep[y]-2*dep[z])%2){cout<<0<<endl;continue;}
if(dep[x]<dep[y])swap(x,y);
int kk=(dep[x]+dep[y]-2*dep[z])/2-1;
int o1=x;
for(int i=18;i>=0;i--)
if(kk>=(1<<i)) kk -= (1<<i),o1=f[o1][i];
if(dep[x]!=dep[y]) cout<<num[f[o1][0]]-num[o1]<<endl;
else
{
kk=(dep[x]+dep[y]-2*dep[z])/2-1;
int o=y;
for(int i=18;i>=0;i--)
if(kk>=(1<<i)) kk -= (1<<i),o=f[o][i];
cout<<n-num[o1]-num[o]<<endl;
}
}
return 0;
}
T3
拆网线
题目描述
企鹅国的网吧们之间由网线互相连接,形成一棵树的结构。现在由于冬天到了,供暖部门缺少燃料,于是他们决定去拆一些网线来做燃料。但是现在有 K 只企鹅要上网和别人联机游戏,所以他们需要把这 K 只企鹅安排到不同的机房(两只企鹅在同一个机房会吵架),然后拆掉一些网线,但是需要保证每只企鹅至少还能通过留下来的网线和至少另一只企鹅联机游戏。
所以他们想知道,最少需要保留多少根网线?
输入格式
第一行一个整数 T ,表示数据组数;
每组数据第一行两个整数 N,K ,表示总共的机房数目和企鹅数目。
第二行 N-1 个整数,第 i 个整数 Ai 表示机房 i+1 和机房 Ai 有一根网线连接(1≤Ai≤i)。
输出格式
每组数据输出一个整数表示最少保留的网线数目。
样例数据 1
输入 [复制]
2
4 4
1 2 3
4 3
1 1 1
输出
2
2
备注
【数据范围】
对于 30% 的数据:N≤15;
对于 50% 的数据:N≤300;
对于 70% 的数据:N≤2000;
对于 100% 的数据:2≤K≤N≤100000,T≤10。
my/std1.cpp
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
inline int read()
{
int X=0,w=1; char ch=0;
while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
return X*w;
}
int n,k,u,v;
struct node{
int u,v,val,next;
}side[1000010];
int cnt=0,first[500010];
void addedge(int u,int v,int val)
{
cnt += 1;
side[cnt].u = u;
side[cnt].v = v;
side[cnt].val = val;
side[cnt].next = first[u];
first[u] = cnt;
}
bool visit[500010];
int son[500010],bro[500010];
int dp[500010][2];
void dfs(int u)
{
int pre=0;
visit[u] = true;
for(int i=first[u];i;i=side[i].next)
{
int v = side[i].v;
if(!visit[v])
{
if(pre==0)son[u]=v;
else bro[pre]=v;
dfs(v);
pre=v;
}
}
dp[u][1]=1;
for(int v=son[u];v;v=bro[v])dp[u][1]+=dp[v][0],dp[u][0]+=dp[v][0];
for(int v=son[u];v;v=bro[v])dp[u][0]=max(dp[u][0],dp[u][1]-1+dp[v][1]-dp[v][0]);
}
int t;
int main()
{
t=read();
while(t--)
{
cnt=0;
memset(dp,0,sizeof(dp));
memset(son,0,sizeof(son));
memset(bro,0,sizeof(bro));
memset(side,0,sizeof(side));
memset(visit,0,sizeof(visit));
memset(first,0,sizeof(first));
n=read(); k=read();
for(int i=1;i<n;i++)
{
u=read();
addedge(u,i+1,1);
addedge(i+1,u,1);
}
addedge(0,1,1);
addedge(1,0,1);
dfs(0);
if(2*dp[1][0]>=k){cout<<(k+1)/2<<endl;}
else cout<<k-dp[1][0]<<endl;
}
return 0;
}
下面是贪心做法
std2.cpp
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;
inline int read(){
int i=0,f=1;
char ch;
for(ch=getchar();!isdigit(ch);ch=getchar())
if(ch=='-') f=-1;
for(;isdigit(ch);ch=getchar())
i=(i<<3)+(i<<1)+(ch^48);
return i*f;
}
int T;
int n,k;
struct node
{
int to,next;
}bian[200050];
int first[100050];
int tot;
int z[100050];
bool bz[100050];
int ans;
int d[100050];
void add(int x,int y)
{
tot++;
bian[tot].next=first[x];
first[x]=tot;
bian[tot].to=y;
}
void dfs(int r)
{
z[r]=1;
bz[r]=1;
for(int u=first[r];u;u=bian[u].next )
{
if(bz[bian[u].to]==0)
{
dfs(bian[u].to);
z[r]+=z[bian[u].to];
}
}
if(z[r]>=2)
{
d[2]++;
z[r]=0;
}
}
int main()
{
// freopen("tree.in","r",stdin);
// freopen("tree.out","w",stdout);
T=read();
while(T--)
{
for(int i=1;i<=tot;i++)
{
bian[i].to=0;
bian[i].next=0;
}
tot=0;
memset(d,0,sizeof(d));
memset(first,0,sizeof(first));
memset(bz,0,sizeof(bz));
memset(z,0,sizeof(z));
ans=0;
n=read();
k=read();
int x;
for(int i=1;i<n;i++)
{
x=read();
add(x,i+1);
add(i+1,x);
}
dfs(1);
while(d[2]!=0)
{
if(k>0)
{
ans++;
}
k=k-2;
d[2]--;
}
if(k<=0)
cout<<ans<<endl;
if(k>0)
{
cout<<ans+k<<endl;
}
}
return 0;
}