2019.10.08
说在前面
今天够爽。
下午考完,晚上给30min改错,再考一场。
刺激。
而且第一场只有165min,我爆5跟时间肯定有一定关系。
方程
【问题描述】
求关于 x 1 , x 2 , ⋯ , x n {x_1,x_2,\cdots,x_n} x1,x2,⋯,xn的方程: x 1 + x 2 + ⋯ + x n = k x_1+x_2+\cdots+x_n=k x1+x2+⋯+xn=k的非负整数解的个数。
【输入格式】
仅一行,包含两个正整数n,k。
【输出格式】
一个整数,表示方程不同解的个数,这个数可能很大,你只需输出mod 20080814的结果。
【输入输出样例1】
equation.in
1 1
equation.out
1
【输入输出样例2】
equation.in
2 2
equation.out
3
【数据范围】
对于50%的数据,n,k<=300
对于80%的数据,n,k<=1000
对于100%的数据,n,k<=100000
分析
很基础的一个组合应用……数学差如我都知道是插板法……
考虑有
k
k
k个
1
1
1摆在一列上,你可以在任意两个球之间插入
n
−
1
n-1
n−1个隔板,然后你就把这些
1
1
1分成了
n
n
n块,也就是
n
n
n个数。
但是因为这些
x
x
x可以取
0
0
0,相当于一个位置可以插很多板,这不好,所以我们让每个
x
x
x都加上
1
1
1,用最易理解也最冗杂的一种方法,令
y
i
=
x
i
+
1
y_i=x_i+1
yi=xi+1,则原问题等价于问
y
1
+
y
2
+
⋯
+
y
n
=
k
+
n
y_1+y_2+\cdots+y_n=k+n
y1+y2+⋯+yn=k+n有几个正整数解。
因为是正整数解了,所以现在每个位置最多只能有一个板子,总共
k
+
n
−
1
k+n-1
k+n−1个板子,选
n
−
1
n-1
n−1个,所以答案就是
C
k
+
n
−
1
n
−
1
=
C
k
+
n
−
1
k
C^{n-1}_{k+n-1}=C^{k}_{k+n-1}
Ck+n−1n−1=Ck+n−1k。
接下来的问题怎么对合数取模。
一种方法是中国剩余定理,中国剩余定理是说:
x
≡
{
x
1
(
m
o
d
p
1
)
x
2
(
m
o
d
p
2
)
⋯
x
n
(
m
o
d
p
n
)
其
中
,
所
有
的
p
都
是
互
质
的
数
,
设
P
=
∏
i
=
1
n
p
i
。
那
么
我
们
就
可
以
找
到
一
个
最
小
的
满
足
上
式
的
正
整
数
x
=
∑
i
=
1
n
×
x
i
×
P
p
i
i
n
v
[
P
p
i
,
p
i
]
。
i
n
v
[
P
p
i
,
p
i
]
就
是
P
p
i
模
p
i
的
逆
元
,
如
果
我
们
质
因
数
分
解
,
那
么
逆
元
就
等
于
(
p
p
i
)
p
i
−
1
了
。
x\equiv \begin{cases} x_1 \pmod{p_1}\\ x_2 \pmod{p_2}\\ \cdots \\ x_n \pmod{p_n}\\ \end{cases} \\ 其中,所有的p都是互质的数,设P=\prod_{i=1}^{n}p_i。\\ 那么我们就可以找到一个最小的满足上式的正整数x=\sum_{i=1}^{n}\times x_i\times\frac{P}{p_i}inv[\frac{P}{p_i},p_i]。\\ inv[\frac{P}{p_i},p_i]就是\frac{P}{p_i}模p_i的逆元,如果我们质因数分解,那么逆元就等于(\frac{p}{p_i})^{p_i-1}了。
x≡⎩⎪⎪⎪⎨⎪⎪⎪⎧x1(modp1)x2(modp2)⋯xn(modpn)其中,所有的p都是互质的数,设P=i=1∏npi。那么我们就可以找到一个最小的满足上式的正整数x=i=1∑n×xi×piPinv[piP,pi]。inv[piP,pi]就是piP模pi的逆元,如果我们质因数分解,那么逆元就等于(pip)pi−1了。
又 ∵ 20080814 = 2 ∗ 13 ∗ 772339 又\because 20080814=2*13*772339 又∵20080814=2∗13∗772339,我们就可以愉快地求出 C k + n − 1 k C^{k}_{k+n-1} Ck+n−1k对 2 , 13 , 772339 2,13,772339 2,13,772339的余数,然后再套公式就是了。
至于怎么求,对
2
和
13
2和13
2和13可以
l
u
c
a
s
定
理
lucas定理
lucas定理,对
772399
772399
772399可以求。
以下是alster大佬的代码,已获得转载许可:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int mod=20080814;//2*13*772339
#define N 100005
int ny2[13+5],ny3[200005+5];
void shai()
{
ny2[0]=ny3[0]=ny2[1]=ny3[1]=1;
for(int i=2;i<13;i++)
ny2[i]=1ll*(13-13/i)*ny2[13%i]%13;
for(int i=2;i<200005;i++)
ny3[i]=1ll*(772339-772339/i)*ny3[772339%i]%772339;
}
int C(int n,int m,int p)
{
// (m+1)*(m+2)*...*n/(n-m)!
if(n<m) return 0;
if(n==0&&m==0) return 1;
if(n==1&&m==0) return 1;
if(n==1&&m==1) return 1;
int ans=1;
for(int i=m+1;i<=n;i++)
ans=1ll*ans*i%p;
for(int i=1;i<=n-m;i++){
if(p==13) ans=1ll*ans*ny2[i]%p;
else ans=1ll*ans*ny3[i]%p;
}
return ans;
}
int lucas(int n,int m,int p)
{
if(n<m) return 0;
if(n==0&&m==0) return 1;
if(n==1&&m==0) return 1;
if(n==1&&m==1) return 1;
return 1ll*lucas(n/p,m/p,p)*C(n%p,m%p,p)%p;
}
int crt(int n,int m)
{
// (m+1)*(m+2)*...*n/(n-m)!
int ans1=lucas(n,m,2),ans2=lucas(n,m,13),ans3=C(n,m,772339);
for(int i=ans3;i<mod;i+=772339)
if(i%2==ans1&&i%13==ans2)
return i;
return 0;
}
int main()
{
shai();
int n,k;
scanf("%d%d",&n,&k);
printf("%d",crt(k+n-1,n-1));
}
以下是Darknesses大佬教我的暴力方法,大家看一看就是了:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
inline void Read(int &p)
{
p=0;
char c=getchar();
while(c<'0' || c>'9') c=getchar();
while(c>='0' && c<='9')
p=p*10+c-'0',c=getchar();
}
const int mod=20080814,maxn=202030;
bool vis[maxn];
long long ans=1;
int n,k,cnt,rep[maxn],pri[maxn];
int main()
{
for(int i=2;i<=500;i++)
{
if(!vis[i]) pri[++cnt]=i;
for(int j=1;j<=cnt && i*pri[j]<=500;j++)
{
vis[i*pri[j]]=1;
if(i%pri[j]==0) break;
}
}
Read(n),Read(k),n=n+k-1;
for(int i=n;i>n-k;i--)
{
int ii=i;
for(int j=1;j<=cnt;j++)
while(ii%pri[j]==0) rep[pri[j]]++,ii/=pri[j];
if(ii!=1) rep[ii]++;
}
for(int i=1;i<=k;i++)
{
int ii=i;
for(int j=1;j<=cnt;j++)
while(ii%pri[j]==0) rep[pri[j]]--,ii/=pri[j];
if(ii!=1) rep[ii]--;
}
for(int i=1;i<=n;i++) while(rep[i]--) (ans*=i)%=mod;
printf("%lld\n",ans);
}
魔板
题目描述
有这样一种魔板:它是一个长方形的面板,被划分成n 行m 列的n*m 个方格。每个方格内有一个小灯泡,灯泡的状态有两种(亮或暗)。我们可以通过若干操作使魔板从一个状态改变为另一个状态。
操作的方式有两种:
(1)任选一行,改变该行中所有灯泡的状态,即亮的变暗、暗的变亮;
(2)任选两列,交换其位置。
当然并不是任意的两种状态都可以通过若干操作来实现互相转化的。你的任务就是根据给定两个魔板状态,判断两个状态能否互相转化。
输入格式
包含多组数据。第一行一个整数k,表示有k 组数据。
每组数据的第一行两个整数n 和m。
以下的n 行描述第一个魔板。每行有m 个数字(0 或1),中间用空格分隔。若第x 行的第y 个数字为0,则表示魔板的第x 行y 列的灯泡为“亮”;否则为“暗”。
然后的n 行描述第二个魔板。数据格式同上。
任意两组数据间没有空行。
输出格式
共 k 行,依次描述每一组数据的结果。
若两个魔板可以相互转化,则输出YES,否则输出NO。(注意:请使用大写字母)
输入样例
2
3 4
0 1 0 1
1 0 0 1
0 0 0 0
0 1 0 1
1 1 0 0
0 0 0 0
2 2
0 0
0 1
1 1
1 1
输出样例
YES
NO
提示
对于30%的数据:k<=5, n+m<=20
对于70%的数据:k<=10, 0<n,m<=40
对于100%的数据:k<=100, 0<n,m<=100
分析
很简单的思路。
我们通过行变换使两个矩阵的某列相等,然后行操作就不能再用了,因为这样的话这两列就不同了。那么剩下的两组n-1列就得是相等的,当然了,因为列可以任意交换,所以就不能看顺序了,于是就枚举,看一个矩阵的每一列是否能在另一个数组各找到一列与之相同。
因为只有一列的情况我会输出no,所以我爆零了。
出题人用心险恶。
但令人不解的是,我这个代码在本机上零点零几sAC,在OJ上会TLE。
然而在我扩大了数据范围之后,发现std以及其他AC的人会TLE掉,我还是能较优秀地跑过去,但我还是在OJ上会TLE。
而且本机是特别慢的那种,特别特别慢。
不懂。
注意,逻辑一定要理顺,不然就会出现如上的问题。
下面的代码是AC的,放心。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
inline void Read(int &p)
{
p=0;
char c=getchar();
while(c<'0' || c>'9') c=getchar();
while(c>='0' && c<='9')
p=p*10+c-'0',c=getchar();
}
const int MAXN=123;
bool vis[MAXN];
int T,n,m,arr[MAXN][MAXN],brr[MAXN][MAXN];
int main()
{
Read(T);
while(T--)
{
Read(n),Read(m);
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) Read(arr[i][j]);
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) Read(brr[i][j]);
if(m==1) {puts("YES");continue;}
bool crl=0;
for(int i=1;i<=n && !crl;i++)
{
int a=0,b=0;
for(int j=1;j<=m;j++)
a+=arr[i][j],b+=brr[i][j];
if(a!=b && a+b!=m) crl=1;
}
if(crl) {puts("NO"); continue;}
for(int j=1;j<=m && !crl;j++)
{
for(int i=1;i<=n;i++)
if(arr[i][1]!=brr[i][j])
for(int k=1;k<=m;k++)
brr[i][k]=!brr[i][k];
memset(vis,0,sizeof vis),vis[j]=1;
for(int a=2;a<=m;a++)
{
bool ok=0;
for(int b=1;b<=m && !ok;b++)
if(!vis[b])
{
bool ko=1;
for(int i=1;i<=n && ko;i++)
ko=(arr[i][a]==brr[i][b]);
if(ko) vis[b]=1,ok=1;
}
if(!ok) break;
if(a==m) crl=1;
}
}
puts(crl?"YES":"NO");
}
}
玩具
问题描述
小沐把玩具扔在地板上,乱七八糟。庆幸的是,有一种特殊的机器人可以收拾玩具。不过他需要
确定哪个机器人去拣哪个玩具。
一共有T 个玩具,整数w[i]表示这个玩具的重量,整数s[i]表示这个玩具的体积。机器人有
两种,分别是:弱机器人和小机器人。
◆有A 个弱机器人。每个弱机器人有一个重量限制X[i],它只能拿起重量严格小于x[i]的玩
具,与玩具的体积大小没有关系。
◆有B 个小机器人。每个小机器人有一个体积限制Y[i],它只能拿起体积严格小于Y[i]的玩
具,与玩具的重量大小没有关系。
每个机器人用1 分钟将一个玩具拿走放好。不同的机器人可以同时拿走并放好不同的玩具。
你的任务是确定机器人是否可以将所有玩具都收拾好,如果是,那么最少用多少时间可以收拾好。
输入格式
第 1 行,三个正整数T,A,B
第2 行A 个整数,表示X[0] x[1]…X[A-1]。
第 2 行B 个整数,表示Y[0] Y[1]…Y[B-1]。
接下来的 T 行每行两个整数,表示W[i]和S[i]
输出格式
一行一个数,即收拾好所有玩具的最短时间。若不论都不能收拾完则输出-1。
输入样例
10 3 2
6 2 9
4 7
4 6
8 5
2 3
7 9
1 8
5 1
3 3
8 7
7 6
10 5
输出样例
3
提示
1<=T<=100,000
0<=A,B<=50,000 且1<=A+B
1<=X[i],Y[i],W[i],S[i]<=2,000,000,000
分析
首先-1的情况很容易判断。
二分答案
t
t
t,代表收拾好所有玩具的时间,也就是说,每个机器人最多处理
t
t
t个玩具。
之后贪心地分配玩具。
我们当然想给小机器人分配体积小但重量大的东西同时给弱机器人分配重量小而体积大的东西。
假设我们把玩具按体积从大到小排序,于是我们从左到右扫过去,对于这个玩具,因为它的体积相对较大,所以我们优先把它交给尽量最弱的弱机器人,交给谁?把弱机器人从小到大,然后随便
u
p
p
e
r
_
b
o
u
n
d
upper\_bound
upper_bound一下就找到了,然后就交给它这个玩具,同时记录它拿了几个玩具,发现它拿满了
t
t
t个,那就把它合并给它的下一个机器人。于是你开一个并查集,你
u
p
p
e
r
_
b
o
u
n
d
upper\_bound
upper_bound以后再在并查集上跑一下,就能找到这次该给谁了。
如果所有弱机器人都拿满了,就分给小机器人。因为我们现在仍在从大体积枚举到小体积,所以我们就优先给最强的小机器人,所以我们把小机器人排序,之后就随便做做。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#pragma GCC optimize(2)
#pragma GCC optimize(3)
inline void Read(int &p)
{
p=0;
char c=getchar();
while(c<'0' || c>'9') c=getchar();
while(c>='0' && c<='9')
p=p*10+c-'0',c=getchar();
}
const int MAXP=1002030,MAXN=52030;
struct point
{
int x,y;
point(int x=0,int y=0){x=x,y=y;}
bool operator < (const point &p) const
{
return x==p.x?y>p.y:x>p.x;
}
}P[MAXP];
int N,A,B,mxx,mxy,ans,arr[MAXN],brr[MAXN],cntx[MAXN],cnty[MAXN],cut[MAXN];
inline int find(int pos){return pos==cut[pos]?pos:cut[pos]=find(cut[pos]);}
inline bool check(int mid)
{
int all=A;
for(int i=1;i<=A;i++) cntx[i]=0;
for(int i=1;i<=B;i++) cnty[i]=0;
for(int i=1;i<=B+1;i++) cut[i]=i;
for(int i=1;i<=N;i++)
{
int pos=find(upper_bound(brr+1,brr+B+1,P[i].y)-brr);
if(pos!=B+1) if((++cnty[pos])==mid) cut[pos]=pos+1;
if(pos==B+1)
{
if(all==0 || P[i].x>=arr[all]) return 0;
all-=((++cntx[all])==mid);
}
}
return 1;
}
int main()
{
Read(N),Read(A),Read(B);
for(int i=1;i<=A;i++) Read(arr[i]),mxx=max(mxx,arr[i]);
for(int i=1;i<=B;i++) Read(brr[i]),mxy=max(mxy,brr[i]);
for(int i=1;i<=N;i++)
{
Read(P[i].x),Read(P[i].y);
if(P[i].x>=mxx && P[i].y>=mxy) return puts("-1"),0;
}
sort(arr+1,arr+A+1),sort(brr+1,brr+B+1),sort(P+1,P+N+1);
register int lef=0,rig=N,mid;
while(lef+1<rig)
if(check(mid=(lef+rig)>>1)) rig=mid;
else lef=mid;
printf("%d\n",rig);
}
无聊的计算
题面
分析
这个
f
(
i
,
j
)
=
k
f(i,j)=k
f(i,j)=k就是
i
%
j
=
k
i\%j=k
i%j=k的意思。
于是本题就是给我们一个数p一个数q一个a数列一个b数列(给你五个值让你递推),问你存在几个有序数对
(
i
,
j
)
(i,j)
(i,j)使得
a
i
b
j
%
p
≤
q
a_i^{b_j}\%p\leq q
aibj%p≤q。
众所周知,虽然n有十万项,但把
a
%
p
a\%p
a%p以后,最多就
p
p
p个值。
众所周知,因为p是质数,
a
p
−
1
%
p
=
1
a^{p-1}\%p=1
ap−1%p=1,所以我们把
b
%
(
p
−
1
)
b\% (p-1)
b%(p−1)以后,是没有影响的,所以b最多就
p
−
1
p-1
p−1个值。
所以所有的
n
∗
m
个
a
i
b
j
n*m个a_i^{b_j}
n∗m个aibj实际上只有
p
×
(
p
−
1
)
p\times(p-1)
p×(p−1)个,还在干什么呢,快来
Θ
(
p
2
)
\Theta(p^2)
Θ(p2)暴力吧!
真是有够无聊的。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
inline void Read(int &p)
{
p=0;
char c=getchar();
while(c<'0' || c>'9') c=getchar();
while(c>='0' && c<='9')
p=p*10+c-'0',c=getchar();
}
inline void Read(int &p,int mod)
{
p=0;
char c=getchar();
while(c<'0' || c>'9') c=getchar();
while(c>='0' && c<='9')
p=p*10+c-'0',c=getchar();
p%=mod;
}
const int MAXP=5555;
long long ans;
int p,q,n,m,t,a1,a2,b1,b2,A,B,C,D,E,F,arr[MAXP],brr[MAXP];
int ksm(int a,int b)
{
int ans=1; a%=p;
while(b)
{
if(b&1) (ans*=a)%=p;
(a*=a)%=p,b>>=1;
}
return ans;
}
int main()
{
Read(p),Read(q),Read(n),Read(a1,p),Read(a2,p),Read(A,p),Read(B,p),Read(C,p),Read(m),Read(b1,p-1),Read(b2,p-1),Read(D,p-1),Read(E,p-1),Read(F,p-1);
arr[a1]++,arr[a2]++; for(int i=3;i<=n;i++) arr[t=((A*a2%p-B*a1%p-C)%p+p)%p]++,a1=a2,a2=t;
brr[b1]++,brr[b2]++; for(int i=3;i<=m;i++) brr[t=((D*b2%(p-1)+E*b1%(p-1)+F)%(p-1)+(p-1))%(p-1)]++,b1=b2,b2=t;
for(int i=0;i<p;i++)
for(int j=0;j<p-1;j++)
if(arr[i] && brr[j])
ans+=1ll*(ksm(i,j)<=q)*arr[i]*brr[j];
cout<<ans<<endl;
}
奇怪的数列
题目描述
nodgd的粉丝太多了,每天都会有很多人排队要签名。
今天有n个人排队,每个人的身高都是一个整数,且互不相同。很不巧,nodgd今天去忙别的事情去了,就只好让这些粉丝们明天再来。同时nodgd提出了一个要求,每个人都要记住自己前面与多少个比自己高的人,以便于明天恢复到今天的顺序。
但是,粉丝们或多或少都是有些失望的,失望使她们晕头转向、神魂颠倒,已经分不清楚哪一边是“前面”了,于是她们可能是记住了前面比自己高的人的个数,也可能是记住了后面比自己高的人的个数,而且他们不知道自己记住的是哪一个方向。
nodgd觉得,即使这样明天也能恢复出一个排队顺序,使得任意一个人的两个方向中至少有一个方向上的比他高的人数和他记住的数字相同。可惜n比较大,显然需要写个程序来解决,nodgd很忙,写程序这种事情就交给你了。
输入格式
第一行输入一个整数n,表示指令的条数。(n<=100000,身高在整型范围)
接下来n行,每行两个整数ai,bi,表示一个人的身高和她记住的数字,保证身高互不相同。
输出格式
输出一行,这个队列里从前到后的每个人的身高。如果有多个答案满足题意,输出字典序最小。如果不存在满足题意的排列,输出“impossible”
输入样例
4
4 1
3 1
6 0
2 0
输出样例
2 4 3 6
提示
在所给出的答案队列中,第一个人身高为2,前面有0个人比他高,所以他是输入的第4个人;第二个人身高为4,右边有1个人比他高,所以他是输入的第1个人;第三个人身高为3,右边有1个人比他高,所以他是输入的第2个人;第四个人身高为6,左边有0个人比他高,所以他是输入的第3个人。
显然,如果排列为“6 3 4 2”也是满足题意的,但是字典序不是最小的。
分析
首先看什么情况无解,容易发现,如果一个人有小于bi个人比她高,她就无解了。
因为无论如何排列,她的b都不会被满足。
……?
?
所以统计每个人有多少人比她高,记为c。
现在我们有解了以后,考虑构造答案数列。
我们把人按身高排序,从矮到高地插入数列。
排序的时候,每个人的b多大无所谓,因为同一身高的人相互之间的b没有影响。
是因为我们拿到的题面还是第一版的,样例里面有重复的。
所以根本不存在同一身高的人。
因为此时我们插入的人,她一定是最高的(没有之一),所以已经插入的人没有能贡献她的 b b b的,所以说,我们就要在她之前或之后留出恰好 b b b个空位置给后来人。同时有要求字典序最小,所以她的位置应该是第 m i n { b + 1 , c − b + 1 } min\{b+1,c-b+1\} min{b+1,c−b+1}。 b + 1 b+1 b+1是在前面留 b b b个空位置,然后自己坐在第 b + 1 b+1 b+1个空位置上, c − b + 1 c-b+1 c−b+1是在后面留 b b b个空位置,然后自己坐在倒数 b + 1 b+1 b+1也就是正数 ( c + 1 ) − ( b + 1 ) + 1 = c − b + 1 (c+1)-(b+1)+1=c-b+1 (c+1)−(b+1)+1=c−b+1个空位置上(总共 c + 1 个 空 位 置 , 倒 数 b + 1 个 就 是 这 么 多 了 c+1个空位置,倒数b+1个就是这么多了 c+1个空位置,倒数b+1个就是这么多了)。
之后怎么求这第多少多少个空位置在哪儿呢?
我们假设这里有一个01序列,0代表非空,1代表空,然后就可以用树状数组维护前缀和,然后二分答案,检测就看这个位置的前缀和是否大于等于这个多少多少。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
inline void Read(int &p)
{
p=0;
char c=getchar();
while(c<'0' || c>'9') c=getchar();
while(c>='0' && c<='9')
p=p*10+c-'0',c=getchar();
}
const int MAXN=102030;
int n,tmp,bit[MAXN],loc[MAXN];
struct people
{
int h,x;
bool operator < (const people &p) const
{
return h<p.h;
}
}arr[MAXN];
#define lowbit(i) (i)&(-(i))
inline void update(int pos,int del){while(pos<=n) bit[pos]+=del,pos+=lowbit(pos);}
inline int getsum(int pos){int ans=0;while(pos) ans+=bit[pos],pos-=lowbit(pos); return ans;}
int main()
{
Read(n);
for(int i=1;i<=n;i++) Read(arr[i].h),Read(arr[i].x),update(i,1);
sort(arr+1,arr+1+n);
bool ok=1;
for(int i=1;i<=n && ok;i++)
{
if(arr[i].x>n-i+1) ok=0;
else
{
int mn=min(arr[i].x+1,n-i+1-arr[i].x);
int lef=1,rig=n,mid;
while(lef<rig)
if(getsum(mid=(lef+rig)>>1)<mn) lef=mid+1;
else rig=mid;
loc[lef]=i,update(lef,-1);
}
}
if(ok) for(int i=1;i<=n;i++) printf("%d%s",arr[loc[i]].h,i==n?"\n":" ");
else puts("impossible");
}
仔细的检查
还没调出来,树hash太强了。