CCF NOIP 2021模拟 10.18
T1
problem
米娅有n个寻宝的地区,在第i个地区寻宝可以带来ai的快乐值,每次米娅会随机选择一个还没有的搜寻过的地区进行寻宝,搜寻第i个地区(i还没有搜寻过)的概率为ai∑j,j还未被搜寻过(包括i)aj,搜寻后会得到ai的快乐值
由于某种原因,米娅搜寻了一号地区后就会停止,米娅想知道她可以获得的快乐值的期望
由于loopers只在一天不断轮回,所以米娅只想知道这个数在mod 109+7意义下的值
【输入格式】
从loopers.in中读入数据
第一行输入一个整数n
第二行输入n个整数a1,a2,…,an
【输出格式】
输出一个整数表示期望的快乐对109+7取模后的结果
【样例一】
输入
4
1 2 3 4
输出
983333348
样例解释
答案为46760
【数据范围与约定】
对于100%的数据,保证1≤n≤107,1≤ai≤5∗107
测试点编号 n ai
1-3 ≤20 ≤5∗107
4-5 ≤107 =1
6-8 ≤1∗105 ≤5∗107
9-10 ≤107 ≤5∗107
注:由于输入规模较大,建议使用读入优化
那个题贴上去概率方程显示不出来我也不会弄,就这样吧,求教。
题解
还是蛮简单,考虑每个点的贡献,就是 a [ i ] × a [ i ] a [ 1 ] + a [ i ] a[i]\times\frac{a[i]}{a[1]+a[i]} a[i]×a[1]+a[i]a[i] ,考虑每个点要么1在它之前要么它先选,证明的话当这两个存在不管任何情况两个的概率比值都是这个。当然需要一个优化,不然复杂度 O ( n l o g v ) O(nlogv) O(nlogv)。类似于技巧吧,先求出 ∑ i = 1 n ( a [ 1 ] + a [ i ] ) \sum_{i=1}^{n}(a[1]+a[i]) ∑i=1n(a[1]+a[i])的逆元和前缀后缀积就可以 O ( n ) O(n) O(n)算了。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e7+10,A=5e7+10;
int n,a[N]; LL sum=1,pre[N],aft[N],ans;
namespace modular{
const LL mod=1e9+7;
inline LL add(const LL a,const LL b){
return a<mod-b?a+b:a-mod+b;
}
inline LL dec(const LL a,const LL b){
return a<b?a-b+mod:a-b;
}
inline LL mul(const LL a,const LL b){
return a*b%mod;
}
inline void Add(LL &a,const LL b){
a=a<mod-b?a+b:a-mod+b;
}
inline void Dec(LL &a,const LL b){
a=a<b?a-b+mod:a-b;
}
inline void Mul(LL &a,const LL b){
a=a*b%mod;
}
inline LL ksm(LL a,LL p){
LL res;
for(res=1;p;Mul(a,a),p>>=1)
(p&1)&&(Mul(res,a),1);
return res;
}
inline LL Inv(const LL a){
return ksm(a,mod-2);
}
inline void Min(LL &a,const LL b){
a=min(a,b);
}
inline void Max(LL &a,const LL b){
a=max(a,b);
}
};
using namespace modular;
#define in read()
const int Mxdt=100000;
inline char gc(){
static char buf[Mxdt],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,Mxdt,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
int t=0,f=0;char v=gc();
while(v<'0')f|=(v=='-'),v=gc();
while(v>='0')t=(t<<3)+(t<<1)+v-48,v=gc();
return f?-t:t;
}
int main(){
// freopen("loopers.in","r",stdin),freopen("loopers.out","w",stdout);
n=in; for(int i=1;i<=n;i++) a[i]=in,Mul(sum,a[1]+a[i]); sum=Inv(sum);
pre[0]=aft[n+1]=1; for(int i=1;i<=n;i++) pre[i]=mul(pre[i-1],a[1]+a[i]); for(int i=n;i>=1;i--) aft[i]=mul(aft[i+1],a[1]+a[i]);
ans=a[1]; for(int i=2;i<=n;i++) Add(ans,mul(mul(a[i],a[i]),mul(sum,mul(pre[i-1],aft[i+1])))); printf("%lld\n",ans);
return 0;
}
T2
problem
rewrite
描述
纵使新月的微光、明灭的星辰、街头的灯火全然散尽
纵使黑暗吞噬一切,我仍不会离你而去
篝酱正在进行对生命理论的研究
篝酱有一个正整数k
这些理论可以看做一个长度为n的序列
篝酱打算给每个理论一个[1,k]中的整数pi来评估这些理论
序列中某些理论是已经被研究过了,评估的数也是确定的
剩下的还被研究的pi可能取[1,k]中的任一整数
某些理论是由关联的,如果两个理论i,j满足ipj,则这一对理论会产生关联
由于生命理论是关乎整个地球大事
所以篝酱想知道所有理论间最多可能有多少对理论会产生关联
【输入格式】
从rewrite.in中读入数据
第一行两个整数 n,k 意义
接下来一行 n 个整数,第 i 个数表示pi,每个数为 [0,k] 中的一个整数,其中 0 表示这个理论还未被研究
【输出格式】
输出一个正整数表示最多可能的关联个数
输出一个整数表示最大的逆序对数量
【样例一】
输入
6 6
5 0 1 4 0 6
输出
7
样例解释
一种方案是将序列填为5 5 1 4 1 6,可以得出此时逆序对数为7且没有更多逆序对的情况
【样例二】
输入
11 9
9 0 3 0 0 4 7 1 0 2 0
输出
44
【数据范围与约定】
对于100%的数据,保证1≤n≤200000,1≤k≤100,0≤pi≤k
测试点编号 n k 特殊限制
1 ≤8 ≤8
2 ≤2∗105 ≤100 保证没有位置为 0
3 ≤2∗105 ≤100 保证只有一个位置为0
4-5 ≤2∗105 ≤100 保证所有位置都为 0
6-7 ≤800 ≤80
8-10 ≤2∗105 ≤100
本机过了交上去全RE。最后找了几天,原因在于数组刚好开炸了,数组刚好开大了,好像510多MB,报错也就报成RE了(我不懂),所以把#define int long long改一下或者优化一下空间就能过了。确实应该算一下空间:三个大数组 ( 2 e 5 + 10 ) × 110 × 3 × 8 ÷ 1024 ÷ 1024 ≈ 503.56 (2e5+10)\times110\times3\times8{\div} 1024{\div} 1024\approx 503.56 (2e5+10)×110×3×8÷1024÷1024≈503.56,在加那么多个小数组程序运行空间确实炸了。数组已经开到 1 e 7 1e7 1e7了确实应该算一下。
题解
我不打算多说,挺恶心的,原来的和加的分开统计,外围枚举第二维,中间斜率优化 O ( n ) O(n) O(n)算,复杂度 O ( n k ) O(nk) O(nk)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long
const int N=2e5+10,A=110;
int n,k,a[N],num[N],cnt[N],pre[N][A],aft[N][A],hv[N][A],f[N],g[N],ans;
int q[N],l,r;
inline int X(const int i){
return num[i];
}
inline int Y(const int i,const int t){
return -g[i]+num[i]*num[i]+hv[i][t];
}
inline int K(const int i){
return num[i];
}
inline double calc(const int j,const int i,const int t){
return (double)(Y(i,t)-Y(j,t))/(1.0*(X(i)-X(j)));
}
#define in read()
inline int read(){
int f=1,k=0; char cp=getchar();
while(cp!='-'&&(cp<'0'||cp>'9')) cp=getchar();
if(cp=='-') f=-1,cp=getchar();
while(cp>='0'&&cp<='9') k=(k<<3)+(k<<1)+cp-48,cp=getchar();
return f*k;
}
signed main(){
// freopen("rewrite.in","r",stdin),freopen("rewrite.out","w",stdout);
n=in,k=in; for(int i=1;i<=n;i++) a[n-i+1]=in; for(int i=1;i<=n;i++) num[i]=num[i-1]+(a[i]==0);
memset(cnt,0,sizeof(cnt)); for(int i=1;i<=n;i++){ for(int j=1;j<=k;j++) pre[i][j]=pre[i][j-1]+cnt[j]; if(a[i]) ++cnt[a[i]]; } //第i位之前小于等于j的个数
memset(cnt,0,sizeof(cnt)); for(int i=n;i>=1;i--){ for(int j=k;j>=1;j--) aft[i][j]=aft[i][j+1]+cnt[j]; if(a[i]) ++cnt[a[i]]; } //第i位之后大于等于j的个数
for(int i=1;i<=n;i++) if(!a[i]) for(int j=1;j<=k;j++) hv[i][j]=hv[i-1][j]+pre[i][j-1]+aft[i][j+1]; else memcpy(hv[i],hv[i-1],sizeof(hv[i]));
for(int i=1;i<=n;i++) if(a[i]) ans+=pre[i][a[i]-1];
for(int t=1;t<=k;t++){ l=r=1;
for(int i=1;i<=n;i++){
if(!a[i]){
while(l<=r&&calc(q[l],q[l+1],t)<K(i)) ++l;
f[i]=K(i)*X(q[l])-Y(q[l],t)+hv[i][t];
while(l<=r&&calc(q[r-1],q[r],t)>calc(q[r],i,t)) --r; q[++r]=i;
}
else f[i]=f[i-1];
} for(int i=1;i<=n;i++) g[i]=max(g[i],f[i]);
} printf("%lld\n",ans+g[n]);
return 0;
}
T3
problem
#5124 【2021.10.18NOIP测试】pockets
描述
眼前这个少女的笑容,和她这副喃喃自语的样子,仿佛与我记忆深处的某个东西产生了共鸣。
月光洒落在少女的侧脸上,居然让我感到一种几乎要落泪的怀念感。
那一定是……
白羽正在做炒饭
总共n盘炒饭排成一行,每盘炒饭有一个美味程度Ai
白羽会不断加工炒饭,每次白羽会选择一段区间[l,r]的炒饭和一个整数k,使得Ai变成(Ai+k)%p
其中p是一个给定的整数
同时为了掌握炒饭的情况,白羽还想知道某两段炒饭美味程度是否依次相等
由于白羽想去吃西瓜棒冰,所以她希望你来帮助她
具体的,白羽希望要求你处理q次以下两种操作:
1 l r k:白羽将Al,Al+1,…Ar变成(Al+k)%p,(Al+1+k)%p,…(Ar+k)%p
2 l r L:白羽想知道Al,Al+1,…Al+L−1与Ar,Ar+1,…Ar+L−1是否相同
【输入格式】
从pockets.in中读入数据
第一行输入三个整数n,q,p
第二行输入n个整数表示初始炒饭的美味程度的A
接下来q行每行输入四个整数op,l,r,k表示如上的操作
【输出格式】
对于白羽每次op=2的询问,输出一行 ye5 或者 n0 表示相同或者不同
【样例一】
输入
8 9 3
0 1 1 0 1 2 2 1
2 1 4 2
1 4 8 2
2 2 5 3
1 7 7 1
2 2 5 3
1 1 7 1
2 1 5 4
1 7 7 2
2 1 5 4
输出
ye5
n0
n0
n0
ye5
【数据范围与约定】
对于100%的数据,保证$1\le n,q\le 500000,2\le p\le 65536,0\le A_i
且对于每次操作,$1\le l\le r\le n,\le k
测试点编号 n,q 特殊限制
T1:1-2 ≤5000
T2:3-4 ≤105 操作2的次数≤100
T3:5-7 ≤80000 p=2
T4:8-9 ≤105 操作1的次数≤100
T5:10-12 ≤105 n,q≤100000,p=65536,每次操作1中k=1
T6:13-16 ≤105 n,q≤100000
T7:17-20 ≤5∗105
注:上面的T只是一个为了方便对应题解部分分的数据类别标号,与题目无实际联系
跑了个样例就走了,没有发数据呀 ,最后AC码变RE,线段树少判个边界,记住要多考虑一下范围吧,线段树经常犯这种问题。
题解
先说一件事,线段树不能维护区间取模、开根与区间加操作,两个操作都只能不带修改保证 l o g log log。应该要用hash,先说部分分,如果没有取模可以区间hash值直接加维护就好了,取模记区间最大暴力修改超过模数的。满分就考虑维护差分,两个区间检查就是起点区间和是否为0且区间内hash相同。dalao他们质疑正确性,我也挺蒙,考虑:差分数字和区间和计算都保证在模数范围内,都是唯一固定的,知道这些推且只能推一个序列,保证了维护一定是正确的,并没有问题。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
const int N=5e5+10,T=N<<2,H1=3777,P1=1000003,H2=4111,P2=1000007;
int n,m,M,opt,x,y,l,c[N],a[N],pw1[N],pw2[N];
#define lp (p<<1)
#define rp (p<<1|1)
#define mid ((pl[p]+pr[p])>>1)
int rt,pl[T],pr[T],sum[T],h1[T],h2[T];
inline void pushup(const int p){
sum[p]=((sum[lp]+sum[rp])%M+M)%M;
h1[p]=(((h1[lp]*pw1[pr[p]-mid])%P1+P1)%P1+h1[rp]+P1)%P1;
h2[p]=(((h2[lp]*pw2[pr[p]-mid])%P2+P2)%P2+h2[rp]+P2)%P2;
}
inline void build(const int l,const int r,const int p=rt){
pl[p]=l,pr[p]=r; if(pl[p]==pr[p]) return sum[p]=h1[p]=h2[p]=a[l],void();
build(l,mid,lp),build(mid+1,r,rp); pushup(p);
}
inline void update(const int x,const int v,const int p=rt){
if(x>n) return;
if(pl[p]==pr[p]) return sum[p]=h1[p]=h2[p]=((sum[p]+v)%M+M)%M,void();
update(x,v,x<=mid?lp:rp); pushup(p);
}
inline int query(const int x,const int y,const int p=rt){
if(x>y) return 0;
if(x==pl[p]&&y==pr[p]) return sum[p];
if(y<=mid) return query(x,y,lp); if(x>mid) return query(x,y,rp);
return ((query(x,mid,lp)+query(mid+1,y,rp))%M+M)%M;
}
inline pii H(const int x,const int y,const int p=rt){
if(y<x) return make_pair(0,0);
if(x==pl[p]&&y==pr[p]) return make_pair(h1[p],h2[p]);
if(y<=mid) return H(x,y,lp); if(x>mid) return H(x,y,rp);
pii h=H(x,mid,lp),hh=H(mid+1,y,rp);
return make_pair((((h.fi*pw1[y-mid])%P1+P1)%P1+hh.fi+P1)%P1,(((h.se*pw2[y-mid])%P2+P2)%P2+hh.se+P2)%P2);
}
#define in read()
inline int read(){
int f=1,k=0; char cp=getchar();
while(cp!='-'&&(cp<'0'||cp>'9')) cp=getchar();
if(cp=='-') f=-1,cp=getchar();
while(cp>='0'&&cp<='9') k=(k<<3)+(k<<1)+cp-48,cp=getchar();
return f*k;
}
signed main(){
// freopen("pockets.in","r",stdin),freopen("pockets.out","w",stdout);
n=in,m=in,M=in; for(int i=1;i<=n;i++) c[i]=in,a[i]=((c[i]-c[i-1])%M+M)%M;
pw1[0]=pw2[0]=1; for(int i=1;i<=n;i++) pw1[i]=(pw1[i-1]*H1)%P1,pw2[i]=(pw2[i-1]*H2)%P2; build(1,n,rt=1);
while(m--){ opt=in,x=in,y=in,l=in;
if(opt==1) update(x,l),update(y+1,-l);
else if(query(x+1,y)==0&&H(x+1,x+l-1)==H(y+1,y+l-1)) puts("ye5"); else puts("n0");
}
return 0;
}
质数 啥乱设的,不知道是不是质数。。。考试忘打query边界了。。。
T4
problem
dohnadohna
描述
一起来干坏事吧
阿熊一行人正在夺拿人材
具体的,这个地图可以看做由n个点m条有向路径组成,而且这个地图不存在环,即构成了一个有向无环图(DAG)
阿熊一行人从1号点出发,到n号点逃出
每个点都有一个人材,第i个点的人材有ai的负担,bi的价值
每当阿熊一行人经过某个节点的时候,可以选择是否夺拿该点的人材
由于为了避免停留过久引发亚总义的追捕,所以他们夺拿的人材负担之和要≤k
阿熊想知道他们最多可以夺拿的人材价值之和为多少,以及有多少种方案可以夺拿这么多的价值
除此之外,阿熊担心亚总义可能会在某个节点设有埋伏,则他们不能经过这个点
因为并不知道哪个点可能设有埋伏,所以他还想知道对每个点知道如果这个点设有埋伏
那么他们可以夺拿的最大价值和方案数
由于方案可能会很多,所以阿熊只想知道方案数对109+7取模后的结果
如果不经过某个点的时候无法到n号点逃出,则输出−1
【输入格式】
从 dohnadohna.in读入
第一行三个整数n,m,k,表示点数,边数和容量
接下来n行每行两个整数表示ai,bi,表示人材的属性
接下来m行每行两个整数u,v,表示u到v有一条有向路径
【输出格式】
输出到 dohnadohna.out
输出 n+1 行,每行两个数
第一行表示不考虑有埋伏的答案
接下来n行表示i号点有埋伏时的答案
【样例一】
输入
4 5 5
1 2
2 3
3 4
4 2
1 2
1 3
2 4
3 4
1 4
输出
6 1
-1
6 1
5 1
-1
【样例二】
输入
8 14 15
2 5
2 7
1 9
5 10
7 6
7 7
15 6
1 5
2 3
3 4
2 5
2 6
4 7
7 8
1 8
1 2
1 3
1 2
1 3
1 4
1 5
1 4
输出
36 2
-1
29 2
20 2
10 1
36 2
36 2
10 1
-1
【数据范围与约定】
对于 100% 的数据,满足1≤n≤105,1≤m≤5∗105,1≤k≤100,1≤ai≤k,1≤bi≤1000
保证初始图联通,经过连接相同两个点的不同边视作不同的方案
测试点编号 n m 特殊限制
1 ≤8 ≤20
2-3 ≤500 ≤2000
4-5 ≤105 ≤5∗105 保证删去除1,n外所有点得到的的最大价值相等
6-10 ≤105 ≤5∗105
是个神仙题,我用最后的10分钟拿到了10分暴力。
题解
先说一下部分分吧,正解拓扑序没怎么搞懂。
10分:每个点重新暴搜(5分钟看题,5分钟码完)
30分:暴搜改成拓扑排序做背包
O
(
n
m
k
)
O(nmk)
O(nmk)
50分:最大值不变,方案改变,就是减去经过该点的方案,这个dp维护个从1-它和它-n的方案直接统计即可
O
(
m
k
+
n
k
)
O(mk+nk)
O(mk+nk)
100分:考虑一个点被删后哪些路径仍会造成贡献。结论:算出每个点的拓扑序(就是拓扑排序的顺序),每个边的贡献就是dfn[x]+1到dfn[y]-1的所有点,就是说这些点都被这条边“越过”了,考虑dfn不连续是因为中间没拓扑完,也就是越过的意思。线段树维护区间修改该边的贡献,边是dp重载运算符计算,最后dfs一遍线段树做出答案。复杂度
O
(
m
k
+
m
l
o
g
n
+
n
l
o
g
n
)
O(mk+mlogn+nlogn)
O(mk+mlogn+nlogn)。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
namespace modular{
const LL mod=1e9+7;
inline LL add(const LL a,const LL b){
return a<mod-b?a+b:a-mod+b;
}
inline LL dec(const LL a,const LL b){
return a<b?a-b+mod:a-b;
}
inline LL mul(const LL a,const LL b){
return a*b%mod;
}
inline void Add(LL &a,const LL b){
a=a<mod-b?a+b:a-mod+b;
}
inline void Dec(LL &a,const LL b){
a=a<b?a-b+mod:a-b;
}
inline void Mul(LL &a,const LL b){
a=a*b%mod;
}
inline LL ksm(LL a,LL p){
LL res;
for(res=1;p;Mul(a,a),p>>=1)
(p&1)&&(Mul(res,a),1);
return res;
}
inline LL Inv(const LL a){
return ksm(a,mod-2);
}
inline void Min(LL &a,const LL b){
a=min(a,b);
}
inline void Max(LL &a,const LL b){
a=max(a,b);
}
};
using namespace modular;
#define int long long
const int N=1e5+10,T=N<<2,K=110;
vector<int> e[N],pre[N]; int du[N];
int n,m,k,x,y,w[N],v[N],dfn[N],idd[N],dfnn;
struct Node{
int v,num; //价值,方案数
Node(const int _v=-1,const int _num=0){
v=_v,num=_num;
}
inline void update(const Node &y){
if(v<y.v) v=y.v,num=y.num;
else if(v==y.v) Add(num,y.num);
}
friend inline Node operator + (const Node &x,const Node &y){
return Node{x.v+y.v,mul(x.num,y.num)};
}
friend inline Node operator + (const Node &x,const int y){
return Node{x.v+y,x.num};
}
}f[N][K],g[N][K],ans[N];
#define lp (p<<1)
#define rp (p<<1|1)
#define mid ((pl[p]+pr[p])>>1)
int rt,pl[T],pr[T]; Node t[T];
inline void build(const int l,const int r,const int p=rt){
pl[p]=l,pr[p]=r,t[p]=Node(); if(pl[p]==pr[p]) return;
build(l,mid,lp),build(mid+1,r,rp);
}
inline void pushdown(const int p){
t[lp].update(t[p]),t[rp].update(t[p]);
}
inline void update(const int x,const int y,const Node &up,const int p=rt){
if(x==pl[p]&&y==pr[p]) return t[p].update(up);
if(y<=mid) update(x,y,up,lp); else if(x>mid) update(x,y,up,rp);
else update(x,mid,up,lp),update(mid+1,y,up,rp);
}
inline void get(const int p=rt){
if(pl[p]==pr[p]) return ans[idd[pl[p]]]=t[p],void();
pushdown(p); get(lp),get(rp);
}
#define in read()
inline int read(){
int f=1,k=0; char cp=getchar();
while(cp!='-'&&(cp<'0'||cp>'9')) cp=getchar();
if(cp=='-') f=-1,cp=getchar();
while(cp>='0'&&cp<='9') k=(k<<3)+(k<<1)+cp-48,cp=getchar();
return f*k;
}
signed main(){
n=in,m=in,k=in; for(int i=1;i<=n;i++) w[i]=in,v[i]=in;
while(m--) x=in,y=in,e[x].push_back(y),pre[y].push_back(x),++du[y];
queue<int> q; for(int i=1;i<=n;i++) if(!du[i]) q.push(i),idd[dfn[i]=++dfnn]=i;
while(!q.empty()){ int p=q.front(); q.pop();
for(int to:e[p]){ --du[to]; if(!du[to]) q.push(to),idd[dfn[to]=++dfnn]=to; }
}
for(int i=1;i<=n;i++){ int p=idd[i];
if(p==1) f[p][0]=Node{0,1},f[p][w[p]]=Node{v[p],1};
for(int fa:pre[p]) for(int j=0;j<=k;j++) if(~f[fa][j].v){
f[p][j].update(f[fa][j]);
if(j+w[p]<=k) f[p][j+w[p]].update(f[fa][j]+v[p]);
}
}
for(int i=n;i>=1;i--){ int p=idd[i];
if(p==n) g[p][0]=Node{0,1},g[p][w[p]]=Node{v[p],1};
for(int fa:e[p]) for(int j=0;j<=k;j++) if(~g[fa][j].v){
g[p][j].update(g[fa][j]);
if(j+w[p]<=k) g[p][j+w[p]].update(g[fa][j]+v[p]);
}
}
for(int i=1;i<=n;i++) for(int j=1;j<=k;j++) f[i][j].update(f[i][j-1]);
build(1,n,rt=1); for(int u=1;u<=n;u++) for(int v:e[u]) if(dfn[u]+1<=dfn[v]-1){
Node mxx; for(int j=0;j<=k;j++) if(~f[u][j].v&&~g[v][k-j].v) mxx.update(f[u][j]+g[v][k-j]);
update(dfn[u]+1,dfn[v]-1,mxx);
}
if(dfn[1]>1) update(1,dfn[1]-1,f[n][k]); if(dfn[n]<n) update(dfn[n]+1,n,f[n][k]);
if(f[n][k].v==-1) puts("-1"); else printf("%lld %lld\n",f[n][k].v,f[n][k].num); get();
for(int i=1;i<=n;i++) if(ans[i].v==-1) puts("-1"); else printf("%lld %lld\n",ans[i].v,ans[i].num);
return 0;
}
预计310实测90。 有什么地方也错了欢迎指正。