您的位置:首页 > 其它

2017年第0届浙江工业大学之江学院程序设计竞赛决赛(完结)

2017-06-06 00:05 597 查看
本来准备要打来着,号都申请好了, 结果打游戏忘了时间。。。。题目质量挺好的,超后悔。

官方题解:萌萌哒的传送门

Problem A: qwb与支教

Time Limit: 1 Sec Memory Limit: 128 MB

Submit: 1613 Solved: 331

[Submit][Status][Web Board]

Description

qwb同时也是是之江学院的志愿者,暑期要前往周边地区支教,为了提高小学生的数学水平。她把小学生排成一排,从左至右从1开始依次往上报数。

玩完一轮后,他发现这个游戏太简单了。于是他选了3个不同的数x,y,z;从1依次往上开始报数,遇到x的倍数、y的倍数或z的倍数就跳过。如果x=2,y=3,z=5;第一名小学生报1,第2名得跳过2、3、4、5、6,报7;第3名得跳过8、9、10,报11。

那么问题来了,请你来计算,第N名学生报的数字是多少?

Input

多组测试数据,处理到文件结束。(测试数据数量<=8000)

每个测试例一行,每行有四个整数x,y,z,N。( 2≤x,y,z≤107,1≤N≤1017)。

Output

对于每个测试例,输出第N名学生所报的数字,每个报数占一行。

Sample Input

2 3 5 2

6 2 4 10000

Sample Output

7

题解:容斥+二分。

代码:

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
ll x,y,z,n;
ll gcd(ll x,ll y)
{
return y==0?x:gcd(y,x%y);
}
ll lcm(ll x,ll y)
{
return x/gcd(x,y)*y;
}
ll solo(ll k)
{
ll ans=k;
ans-=k/x+k/y+k/z;
ans+=k/lcm(x,y)+k/lcm(x,z)+k/lcm(y,z);
ans-=k/(lcm(lcm(x,y),z));
return ans;
}
int main()
{
while(~scanf("%lld%lld%lld%lld",&x,&y,&z,&n))
{
ll l=1;
ll r=(~(1ll<<63))>>1;
ll mid;
ll ans=0;
while(r>=l)
{
mid=(r+l)>>1;
if(solo(mid)>=n)
{
ans=mid;
r=mid-1;
}
else
l=mid+1;
}
printf("%lld\n",ans);
}
}


Problem B: qwb与矩阵

Time Limit: 2 Sec Memory Limit: 128 MB

Submit: 1192 Solved: 251

[Submit][Status][Web Board]

Description

做完了辣么多的数学题,qwb好好睡了一觉。但是他做了一个梦:

有一个n*m的矩阵,qwb在这个矩阵的左上角(1,1),终点在右下角(n,m)。

每个格子中有小钱钱,也可能没有,还有可能是要交过路费的,并且行走方向必须是靠近终点的方向。

往下走一次只能走一格,往右走一次可以走一格也可以走到当前列数的倍数格。

比如当前格子是(x,y),那么可以移动到(x+1,y),(x,y+1)或者(x,y*k),其中k>1。

qwb希望找到一种走法,使得到达右下角时他能够有最多的小钱钱。

你能帮助他吗?

Input

第一行是测试例数量 T (T<=100),接下来是T组测试数据。

每组测试数据的第一行是两个整数n,m,分别表示行数和列数(1<=n<=20,1<=m<=10000);

接下去给你一个n*m的矩阵,每个格子里有一个数字 k (-100<=k<=100)代表小钱钱的数量。 ∑nm<=3,000,000

Output

每组数据一行,输出L先生能够获得小钱钱的最大值(可能为负数)。

Sample Input

1

3 8

9 10 10 10 10 -10 10 10

10 -11 -1 0 2 11 10 -20

-11 -11 10 11 2 10 -10 -10

Sample Output

52

题解:搜索。

代码:

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
int n,m,t;
int dp[30][10020];
int a[30][10020];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
dp[i][j]=-100000;
}
}
dp[1][1]=a[1][1];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i>1)dp[i][j]=max(dp[i][j],dp[i-1][j]+a[i][j]);
if(j>1)dp[i][j]=max(dp[i][j],dp[i][j-1]+a[i][j]);
for(int k=j+j;k<=m;k+=j)
dp[i][k]=max(dp[i][k],dp[i][j]+a[i][k]);
}
}
printf("%d\n",dp
[m]);
}
}


Problem D: qwb与神奇的序列

Time Limit: 1 Sec Memory Limit: 128 MB

Submit: 1297 Solved: 223

[Submit][Status][Web Board]

Description

qwb又遇到了一道题目:

有一个序列,初始时只有两个数x和y,之后每次操作时,在原序列的任意两个相邻数之间插入这两个数的和,得到新序列。举例说明:

初始:1 2

操作1次:1 3 2

操作2次:1 4 3 5 2

……

请问在操作n次之后,得到的序列的所有数之和是多少?

Input

多组测试数据,处理到文件结束(测试例数量<=50000)。

输入为一行三个整数x,y,n,相邻两个数之间用单个空格隔开。(0 <= x <= 1e10, 0 <= y <= 1e10, 1 < n <= 1e10)。

Output

对于每个测试例,输出一个整数,占一行,即最终序列中所有数之和。

如果和超过1e8,则输出低8位。(前导0不输出,直接理解成%1e8)

Sample Input

1 2 2

Sample Output

15

题解:矩阵快速幂

代码:

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
const int  mod=1e8;
struct Matrix
{
ll m[3][3];
};
Matrix Mul(Matrix a,Matrix b)
{
Matrix c;
memset(c.m,0,sizeof(c.m));
for(int i=0; i<2; i++)
for(int j=0; j<2; j++)
for(int k=0; k<2; k++)
{
c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j]+mod)%mod;

}
return c;
}
Matrix fastm(Matrix a,ll n)
{
Matrix res;
memset(res.m,0,sizeof(res.m));
res.m[0][0]=1,res.m[0][1]=-1;
while(n)
{
if(n&1)
res = Mul(res,a);
n>>=1;
a = Mul(a,a);
}
return res;
}
Matrix init()
{
Matrix pp;
memset(pp.m,0,sizeof(pp.m));
pp.m[0][0]=3,pp.m[0][1]=0;
pp.m[1][0]=1,pp.m[1][1]=1;
return pp;
}
int main()
{
ll x,y,n;
while(~scanf("%lld%lld%lld",&x,&y,&n))
{
Matrix p=fastm(init(),n);
ll cnt=p.m[0][0];
printf("%lld\n",(((x+y)%mod)*cnt)%mod);
}
}


Problem G: qwb去面试

Time Limit: 1 Sec Memory Limit: 128 MB

Submit: 1815 Solved: 306

[Submit][Status][Web Board]

Description

某一天,qwb去WCfun面试,面试官问了他一个问题:把一个正整数n拆分成若干个正整数的和,请求出这些数乘积的最大值。

qwb比较猥琐,借故上厕所偷偷上网求助,聪明的你能帮助他吗?

Input

第一行为一个正整数T.(T<=100000)

接下来T行,每行一个正整数n(n<=1e9),意义如题目所述。

Output

每一行输出一个整数,表示乘积的最大值,由于答案可能很大,请将答案对109+7取模后输出。

Sample Input

2

2

5

Sample Output

2

6

题解:思维。

代码:

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
const int mod=1e9+7;
int t;
ll n,x,y;
ll q_mod(ll x,ll y)
{
ll ans=1;
while(y)
{
if(y&1)
ans=ans*x%mod;
y>>=1;
x=x*x%mod;
}
return ans;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%lld",&n);
if(n<5) {printf("%lld\n",n);continue;}
x=n/3;
y=n%3;
if(y==1) x--,y=4;
if(y==0) y=1;
printf("%lld\n",q_mod(3,x)*y%mod);
}
}


Problem J: qwb又偷懒了

Time Limit: 1 Sec Memory Limit: 128 MB

Submit: 730 Solved: 123

[Submit][Status][Web Board]

Description

qwb最近在做一个群众收入统计。ta非常懒,以至于忘记了今天领导要来视察。所以急忙催下属去做统计。

在接下来长度为n的时间里,每个单位时间都有事情发生,可能会发下以下两种事件:

1)下属递交了一份调查报告,由于太匆忙,上面只有一个整数x,代表一个居民的收入。

2)领导来视察了,领导会来询问,收入在区间[l,r]内的居民的平均收入,qwb需要给出回答。

qwb非常讨厌小数,所以qwb上报时都会省略小数部分。如果上报时统计的人数为0,qwb就暴露了他偷懒的事情,他就会zhizhiwuwu。

Input

多组测试数据,处理到文件末尾。

每组测试数据的第一行为一个正整数n(0<=100000),确保所有的n的和不超过300000

接下来n行,

当第一个数为0时,代表操作1,后面跟着一个整数x(0<=x<=1000000),意义如题目所述。

当第一个数为1时,代表操作2,后面跟着两个整数l,r(0<=l<=r<=1000000),意义如题目描述。

Output

对于每一个领导的询问,给出一个回答,如果统计区间的人数为零,则输出”zhizhiwuwu”。(不带引号)

每个测试例之后输出一个空行。

Sample Input

3

0 1

0 3

1 1 3

2

0 1

1 2 2

Sample Output

2

zhizhiwuwu

题解:BIT

代码:

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
const int N=1e6+7;
int n,op;
ll l,r,x;
ll sum
,cnt
;
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int y)
{
for(int i=++x;i<N;i+=lowbit(i))
sum[i]+=y,cnt[i]++;
}
ll getsum(int x)
{
ll ans=0;
for(int i=++x;i;i-=lowbit(i))
ans+=sum[i];
return ans;
}
ll getcnt(int x)
{

ll ans=0;
for(int i=++x;i;i-=lowbit(i))
ans+=cnt[i];
return ans;
}
int main()
{
while(~scanf("%d",&n))
{
memset(sum,0,sizeof(sum));
memset(cnt,0,sizeof(cnt));
while(n--)
{
scanf("%d",&op);
if(op)
{
scanf("%lld%lld",&l,&r);
ll a=getsum(r)-getsum(l-1);
ll b=getcnt(r)-getcnt(l-1);
if(b==0)
printf("zhizhiwuwu\n");
else
printf("%lld\n",a/b);
}
else
{
scanf("%lld",&x);
update(x,x);
}
}
printf("\n");
}
}


Problem E: qwb和李主席

Time Limit: 4 Sec Memory Limit: 128 MB

Submit: 494 Solved: 65

[Submit][Status][Web Board]

Description

qwb和李主席打算平分一堆宝藏,他们想确保分配公平,可惜他们都太懒了,你能帮助他们嘛?

Input

输入包含多组测试数据,处理到文件结束。

每组测试数据的第一行是一个正整数N(0 <= N <=36 )表示物品的总个数.。

接下来输入N个浮点数(最多精确到分),表示每个物品的价值V(0

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
int n;
double val[40];
double a[10000000];
double ans,tot;
int la;
double solo(double cnt)
{
int l=1,r=la-1,mid,res=-1;
while(r>=l)
{
mid=(r+l)>>1;
if(a[mid]+cnt>=tot/2.0)
{
res=mid;
r=mid-1;
}
else
l=mid+1;
}
return min(abs(tot-a[res]*2-cnt*2),abs(tot-a[res-1]*2-cnt*2));

}
int main()
{
while(~scanf("%d",&n))
{
ans=1e18;
int lena=n/2;
int lenb=n-lena;
tot=0.0;
for(int k=0;k<n;k++)
{
scanf("%lf",&val[k]);
tot+=val[k];
}
la=1;
for(int i=0;i<(1<<lena);i++)
{
double cnt=0.0;
for(int j=0;j<lena;j++)
{
if(i&(1<<j))
{
cnt+=val[j];
}
}
a[la++]=cnt;
}
sort(a+1,a+la);
// for(int i=1;i<la;i++) cout<<a[i]<<" ";
//cout<<endl;
for(int i=0;i<(1<<lenb);i++)
{
double cnt=0.0;
for(int j=0;j<lenb;j++)
{
if(i&(1<<j))
cnt+=val[lena+j];
//cout<<cnt<<endl;
}
// cout<<cnt<<endl;
ans=min(ans,solo(cnt));
}
printf("%.2f\n",ans);
}
}


Problem K: qwb与小数

Time Limit: 1 Sec Memory Limit: 128 MB

Submit: 482 Solved: 107

[Submit][Status][Web Board]

Description

qwb遇到了一个问题:将分数a/b化为小数后,小数点后第n位的数字是多少?

做了那么多题,我已经不指望你能够帮上他了。。。

Input

多组测试数据
15afd
,处理到文件结束。(测试数据<=100000组)

每组测试例包含三个整数a,b,n,相邻两个数之间用单个空格隔开,其中0 <= a <1e9,0 < b < 1e9,1 <= n < 1e9。

Output

对于每组数据,输出a/b的第n位数,占一行。

Sample Input

1 2 1

1 2 2

Sample Output

5

0

题解:思维。

代码:

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
ll a,b,n;
ll q_mod(ll x,ll y)
{
ll ans=1;
while(y)
{
if(y&1) ans=ans*x%b;
y>>=1;
x=x*x%b;
}
return ans;
}
int main()
{
while(~scanf("%lld%lld%lld",&a,&b,&n))
{
printf("%lld\n",a%b*q_mod(10,n-1)%b*10/b);
}
}


Problem F: qwb has a lot of Coins

Time Limit: 1 Sec Memory Limit: 128 MB

Submit: 760 Solved: 252

[Submit][Status][Web Board]

Description

qwb has a lot of coins. One day, he decides to play a game with his friend using these coins. He first puts some of his coins into M piles, each of which is composed of Ni (1<=i<=M) coins. Then, the two players play the coin game in turns. Every step, one can remove one or more coins from only one pile. The winner is the one who removes the last coin.

Then comes the question: How many different ways the first player can do that will ensure him win the game?

Input

Input contains multiple test cases till the end of file. Each test case starts with a number M (1 <= M<= 1000) meaning the number of piles. The next line contains M integers Ni (1 <= Ni <= 1e9, 1 <= i<= M) indicating the number of coins in pile i.

Output

For each case, put the method count in one line.

If the first player can win the game, the method count is the number of different ways that he can do to ensure him win the game, otherwise zero.

Sample Input

3

1 2 3

1

1

Sample Output

0

1

题解:nim博弈

代码:

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
ll a[1010];
int main()
{
int n;
while(~scanf("%d",&n))
{
ll ans=0;
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]),ans^=a[i];
ll sum=0;
for(int i=1;i<=n;i++)
{
if(a[i]>(ans^a[i]))
sum++;
}
printf("%lld\n",sum);
}
}


Problem C: 勤劳的ACgirls

Time Limit: 1 Sec Memory Limit: 128 MB

Submit: 163 Solved: 69

[Submit][Status][Web Board]

Description

zjc的ACgirls队的队员最近比较忙,为了能够取得更好的比赛成绩,他们制定了一个m天a掉n题的计划,a掉一题可以是这m天的任何时候。

为了表示对acmer事业的热爱,队长wc要求每天必须至少要ac掉k题,这m天每天ac掉的题数可以用一个m元组表示。

设不同的m元组一共有c个,请问c的末尾有多少个0?(如果c是0,输出0)

Input

多组测试数据,处理到文件结束。(测试例数量<=160000)

输入的每一行是一个测试例,分别是m、n和k(0<=m,n,k<=1e9),含义如前所述。

Output

每组测试例中m元组的数量的末尾0的个数,占一行。

Sample Input

3 11 0

3 11 1

999 99999 4

Sample Output

0

0

5

HINT

题解;组合数学

代码:

#include <bits/stdc++.h>
typedef long long int LL;
using namespace std;

LL solve(LL x,int y){
LL sum = 0;
while(x){
x/=y;
sum+=x;
}
return sum;
}

LL n,m,k;
int main(){
while(~scanf("%lld%lld%lld",&m,&n,&k)){
n=n-m*k;
if(n<=0) puts("0");
else{
LL sum =solve(n+m-1,5)-solve(n,5)-solve(m-1,5);
LL sum2=solve(n+m-1,2)-solve(n,2)-solve(m-1,2);
sum=min(sum,sum2);
sum=max(0ll,sum);
printf("%lld\n",sum);
}
}
return 0;
}


Problem H: qwb与学姐

Time Limit: 1 Sec Memory Limit: 128 MB

Submit: 176 Solved: 61

[Submit][Status][Web Board]

Description

qwb打算向学姐表白,可是学姐已经受够了他的骚扰,于是出了一个题想难住他:

已知一幅n个点m条边的无向图,定义路径的值为这条路径上最短的边的长度,

现在有 k个询问,

询问从A点到B点的所有路径的值的最大值。

qwb听完这个问题很绝望啊,聪明的你能帮帮他吗?

Input

一组数据。

第一行三个整数n,m,k (1<=N<=50000,m<=200000,k<=100000)。

第2..m+1行:三个正整数:X, Y, and D (1 <= X <=N; 1 <= Y <= N,1<=D<=215) 表示X与Y之间有一条长度为D的边。

第m+2..m+k+1行: 每行两个整数A B(1<=A,B<=n且A≠B),意义如题目描述。

保证图连通。

Output

对于每个询问输出一行,一共k行,每行输出A点到B点的所有路径的值的最大值。

Sample Input

4 5 3

1 2 6

1 3 8

2 3 4

2 4 5

3 4 7

2 3

1 4

3 4

Sample Output

6

7

7

题解:mst+树链剖分。

代码:

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
const int N=200010;
int read(){
int x=0;char ch = getchar();
while('0'>ch||ch>'9')ch=getchar();
while('0'<=ch&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x;
}
int n,m,k,cnt,tot;
int dep
,fa
,siz
,son
;
int f
;
int sum[N<<2];
int u,v;
struct node
{
int u,v,w;
bool operator <(const node &t)const
{
return w>t.w;
}
}a
;
int head[N<<2];
int b
;
struct nod
{
int to,next,w;
}edge[N<<2];
int find(int x)
{
return x==f[x]?x:f[x]=find(f[x]);
}
void join(int x,int y)
{
int xx=find(x);
int yy=find(y);
if(xx!=yy)
f[xx]=yy;

}
void add(int u,int v,int w)
{
edge[cnt].to=v,edge[cnt].next=head[u],edge[cnt].w=w,head[u]=cnt++;
edge[cnt].to=u,edge[cnt].next=head[v],edge[cnt].w=w,head[v]=cnt++;
}
void mst()
{
for(int i=1,su=0;i<=m&&su<n-1;i++)
{
if(find(a[i].u)==find(a[i].v)) continue;
join(a[i].u,a[i].v);
add(a[i].u,a[i].v,a[i].w);
su++;
}
}
void dfs1(int u,int f,int d)
{
dep[u]=d,fa[u]=f,siz[u]=1,son[u]=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{

int v=edge[i].to;
if(v==f)continue;
b[v]=edge[i].w;
dfs1(v,u,d+1);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v]) son[u]=v;
}
}
int top
,pre
,tree
;
void dfs2(int u,int tp)
{
top[u]=tp,tree[u]=++tot,pre[tree[u]]=u;
if(!son[u]) return ;
dfs2(son[u],tp);
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}

}
int lca(int x,int y)
{
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(dep[fx]<dep[fy]) swap(x,y),swap(fx,fy);
x=fa[fx],fx=top[x];
}
if(dep[x]>dep[y])swap(x,y);
return x;
}
void init()
{
cnt=0;
tot=0;
memset(head,-1,sizeof(head));
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++) f[i]=i;
}
void pushup(int rt)
{
sum[rt]=min(sum[rt<<1],sum[rt<<1|1]);
}
void build(int l,int r,int rt)
{
if(l==r)
{
sum[rt]=b[pre[l]];
return ;
}
int mid=(r+l)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
pushup(rt);
}
int query_min(int l,int r,int ll,int rr,int rt)
{
if(ll<=l&&rr>=r)
{
return sum[rt];
}
int ans=1e7;
int mid=(r+l)>>1;
if(ll<=mid)
ans=min(ans,query_min(l,mid,ll,rr,rt<<1));
if(rr>mid) ans=min(ans,query_min(mid+1,r,ll,rr,rt<<1|1));
return ans;
}
int find_min(int x,int y)
{
int ans=1e7;
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(dep[fx]<dep[fy]) swap(x,y),swap(fx,fy);
ans=min(ans,query_min(1,n,tree[fx],tree[x],1));
x=fa[fx],fx=top[x];
}
if(dep[x]>dep[y]) swap(x,y);
ans=min(ans,query_min(1,n,tree[x]+1,tree[y],1));
return ans;
}
int main()
{
n=read(),m=read(),k=read();
init();
for(int i=1;i<=m;i++)
{
a[i].u=read();
a[i].v=read();
a[i].w=read();
}
sort(a+1,a+1+m);
mst();
dfs1(1,0,1);
dfs2(1,1);
b[1]=1e8;
build(1,n,1);
while(k--)
{
u=read();
v=read();
int lc=lca(u,v);
int lmin=find_min(u,lc);
int rmin=find_min(v,lc);
printf("%d\n",min(lmin,rmin));
}
}


Problem L: qwb与整数对

Time Limit: 1 Sec Memory Limit: 128 MB

Submit: 214 Solved: 34

[Submit][Status][Web Board]

Description

qwb又遇到了一道数学难题,你能帮助他吗?

给出两个整数n和m,请统计满足0<a<b<n并且使得 (a2+b2+m)/(ab) 的结果是整数的整数对(a,b)的个数。

Input

本题包含多组测试例 。当测试例数据是n=m=0时,表示输入结束。(测试例数量<6000)

每个测试例一行,是两个整数n和m。输入保证0≤n≤1000,-20000

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=6010;
int a
,b
,ans
;
int x,y;
vector<int>p[40010];
int main()
{
int cnt=1;
while(1)
{
scanf("%d%d",&x,&y);
if(x==0&&y==0) break;
a[cnt]=x;
b[cnt]=y;
p[y+20000].push_back(cnt);
cnt++;
}
for(int i=1;i<=1000;i++)
{
for(int j=1+i;j<=1000;j++)
{
int x=i*j-(i*i+j*j)%(i*j);
for(int k=x;k<=20000;k+=i*j)
{
int siz=p[k+20000].size();
for(int o=0;o<siz;o++)
{
if(a[p[k+20000][o]]>j)
ans[p[k+20000][o]]++;
}

}
for(int k=x-i*j;k>=-20000;k-=i*j)
{
int siz=p[k+20000].size();
for(int o=0;o<siz;o++)
{
if(a[p[k+20000][o]]>j)
ans[p[k+20000][o]]++;
}

}

}
}
for(int i=1;i<cnt;i++)
{
printf("Case %d: %d\n",i,ans[i]);
}
}


Problem M: qwb与二叉树

Time Limit: 1 Sec Memory Limit: 128 MB

Submit: 208 Solved: 58

[Submit][Status][Web Board]

Description

某一天,qwb正在上数据结构课。老师在讲台上面讲着二叉树,qwb在下面发着呆。

突然qwb想到一个问题:对于一棵n个无编号节点,m个叶子的有根二叉树,有多少种形态呐?你能告诉他吗?

Input

多组输入,处理到文件结束,大约有104组数据。

每一组输入一行,两个正整数n,m(0≤m≤n≤50),意义如题目所述。

Output

每一行输出一个数,表示相应询问的答案,由于答案可能很大,请将答案对109+7取模后输出。

Sample Input

4 2

10 5

Sample Output

6

252

HINT

题解:记忆化搜索。

代码:

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
const int N=200010;
const int mod=1e9+7;
int read(){
int x=0;char ch = getchar();
while('0'>ch||ch>'9')ch=getchar();
while('0'<=ch&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x;
}
ll dp[100][100];
ll dfs(int  x,int  y)
{
if(dp[x][y]!=-1) return dp[x][y];
if(x<y*2-1||x<=0||y<=0) return dp[x][y]=0;
int xx=x-1;
int yy=y;
ll res=0;
res=(2ll*dfs(xx,yy))%mod;
for(int i=0;i<xx;i++)
{
for(int j=1;j<yy;j++)
{
res=(res+1ll*dfs(i,j)*dfs(xx-i,yy-j))%mod;
}
}
return dp[x][y]=res;
}
int main()
{
memset(dp,-1,sizeof(dp));
dp[1][1]=1;
int n,m;
while(~scanf("%d%d",&n,&m))
{
printf("%lld\n",dfs(n,m));
}
}


Problem I: qwb VS 去污棒

Time Limit: 2 Sec Memory Limit: 256 MB

Submit: 84 Solved: 28

[Submit][Status][Web Board]

Description

qwb表白学姐失败后,郁郁寡欢,整天坐在太阳底下赏月。在外人看来,他每天自言自语,其实他在和自己的影子“去污棒”聊天。

去污棒和qwb互相出题考验对方,去污棒问了qwb这样一个问题:

现已知一个有n个正整数的序列a[1],a[2]…a
,接下来有m个操作

操作一共有两种:

1.在序列末尾添加一个数x。

2.查询suf[p] xor x的最大值,其中xor是异或 ,l<=p<=r,

suf[t]表示从t开始的后缀的异或和,即suf[t]=a[t] xor a[t+1] xor …xor a[len],len为序列长度。

Input

第一行一个整数T(<=5),表示一共有T组数据。

每组数据第一行两个整数n(<=200000),m(<=200000),意义如上所述。

随后一行有n个数,表示初始序列。

随后m行,每行表示一个操作。

操作有两种,1: x 表示在末尾添加一个x,2: l r x表示查询suf[p] xor x的最大值,其中l<= p <= r,

所有数及x不超过224 且保证所有操作合法。

Output

每组测试数据的第一行输出”Case x:”,x为数据组数的标号,从1开始。

接下来,对每个操作2输出一行答案。

Sample Input

1

5 5

1 2 3 4 5

2 1 3 4

1 10

1 7

2 4 4 5

2 1 5 19

Sample Output

Case 1:

6

9

31

题解:可持久化01字典树.

代码:

#include <bits/stdc++.h>
typedef long long int LL;
using namespace std;

#define abs(x) (((x)>0)?(x):-(x))

const int N = 400000+10;
const int MOD  = 1e8;

int read(){
int x=0;char ch = getchar();
while('0'>ch||ch>'9')ch=getchar();
while('0'<=ch&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x;
}

/**********************************/

int trie[N*40][2],sz[N*40],rt
;
int n,m,cnt,sum;
char s[10];

int update(int pre,int i,int x){
int now=++cnt;
if(0==i){
trie[now][0]=trie[now][1]=0;
sz[now]=sz[pre]+1;
return now;
}
int bt=((x>>(i-1))&1);
trie[now][1-bt]=trie[pre][1-bt];
trie[now][bt]=update(trie[pre][bt],i-1,x);
sz[now]=sz[trie[now][0]]+sz[trie[now][1]];
return now;
}

int query(int rt1,int rt2,int i,int x){
if (i==0) return 0;
int bt=((x>>(i-1))&1);
if (sz[trie[rt2][1-bt]]-sz[trie[rt1][1-bt]])
return (1<<(i-1))+query(trie[rt1][1-bt],trie[rt2][1-bt],i-1,x);
else
return query(trie[rt1][bt],trie[rt2][bt],i-1,x);
}

int main(){
int _=read(),kcase=0;
while(_--){
n=read(),m=read();
rt[0]=trie[0][0]=trie[0][1]=sz[0]=sum=0;
rt[0]=update(rt[0],25,0);
for (int i=1;i<=n;i++){
sum^=read();
rt[i]=update(rt[i-1],25,sum);
}

printf("Case %d:\n",++kcase);
while (m--){
int l,r;
scanf("%s",s+1);
if (s[1]=='1'){
sum^=read();
n++;rt
=update(rt[n-1],25,sum);
}
else{
l=read()-1,r=read()-1;
printf("%d\n",query(rt[l-1],rt[r],25,sum^read()));
}
}
}
return 0;
}


完结——撒花。

个别题会单独拿出来。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐