NOIP2020
再次写挂。 考前两三天每天平均打两场酒馆战旗,均吃鸡,$rp--$ ,$XJ$ 信心赛被反向打击,$rp--$。
期望得分 $100+100+40+60=300$ 。 实际得分 $60+92+40+35=227$ 。
A
没写高精度,还写了个先乘后除,不卡我卡谁?
拓扑,高精度。 由于过懒写了个 $int128$ 。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<vector> #include<queue> #define pb push_back #define mp make_pair #define fi first #define se second #define int long long using namespace std; inline int read(){ int f=1,ans=0; char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int MAXN=1e5+11; int gcd(int a,int b){return !b?a:gcd(b,a%b);} int N,M,Ansx[MAXN],Ansy[MAXN],d[MAXN]; vector<int> vec[MAXN]; queue<int> que; signed main(){ N=read(),M=read(); for(int i=1;i<=N;i++){ int len=read(); for(int j=1;j<=len;j++){int x=read();d[x]++;vec[i].pb(x);} } for(int i=1;i<=N;i++) if(!d[i]){Ansx[i]=Ansy[i]=1;que.push(i);} while(!que.empty()){ int xx=que.front(); que.pop(); int siz=vec[xx].size(); int rx=Ansx[xx],ry=Ansy[xx]*siz,t=gcd(rx,ry); rx/=t,ry/=t; for(int i=0;i<siz;i++){ int v=vec[xx][i]; if(!Ansx[v]&&!Ansy[v]){Ansx[v]=rx,Ansy[v]=ry;} else{ int X=Ansx[v]*ry+Ansy[v]*rx,Y=Ansy[v]*ry,T=gcd(X,Y); X/=T,Y/=T; Ansx[v]=X,Ansy[v]=Y; }d[v]--; if(!d[v]) que.push(v); } } for(int i=1;i<=N;i++) if(!vec[i].size()) printf("%lld %lld\n",Ansx[i],Ansy[i]); return 0; }
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<vector> #include<queue> #define pb push_back #define mp make_pair #define fi first #define se second #define int __int128 using namespace std; inline int read(){ int f=1,ans=0; char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int MAXN=2e5+11; int gcd(int a,int b){return !b?a:gcd(b,a%b);} int N,M,Ansx[MAXN],Ansy[MAXN],d[MAXN]; vector<int> vec[MAXN]; queue<int> que; void write(int x){if(!x) return;write(x/10);putchar(x%10+'0');} void print(int x){if(!x) printf("0");else write(x);} signed main(){ freopen("water.in","r",stdin); freopen("water.out","w",stdout); N=read(),M=read(); for(int i=1;i<=N;i++){ int len=read(); for(int j=1;j<=len;j++){int x=read();d[x]++;vec[i].pb(x);} } for(int i=1;i<=N;i++) if(!d[i]){Ansx[i]=Ansy[i]=1;que.push(i);} while(!que.empty()){ int xx=que.front(); que.pop(); int siz=vec[xx].size(); int rx=Ansx[xx],ry=Ansy[xx]*siz,t=gcd(rx,ry); rx/=t,ry/=t; for(int i=0;i<siz;i++){ int v=vec[xx][i]; if(!Ansx[v]&&!Ansy[v]){Ansx[v]=rx,Ansy[v]=ry;} else{ int Lcm=Ansy[v]*(ry/gcd(Ansy[v],ry)); int X=Ansx[v]*(Lcm/Ansy[v])+rx*(Lcm/ry),Y=Lcm,T=gcd(X,Y); X/=T,Y/=T; Ansx[v]=X,Ansy[v]=Y; }d[v]--; if(!d[v]) que.push(v); } } for(int i=1;i<=N;i++) if(!vec[i].size()){print(Ansx[i]); printf(" "); print(Ansy[i]); printf("\n");} return 0; }
B
写了个 $O(Tn(\ln n+26))$ 的做法。自然溢出 $32$ 位机子不太行(这东西上次写还由于操作不对爆零了)。
暴力枚举 $AB$,利用 $hash$ 判断,为了平衡瓶颈前缀和暴力维护前缀 $f$。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<vector> #include<queue> #define LL long long #define pb push_back #define mp make_pair #define fi first #define se second using namespace std; inline int read(){ int f=1,ans=0; char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int MAXN=1048581; char str[MAXN]; int N,cas,suf[MAXN],Num[28],res,S[28],pre[MAXN],SS[28]; LL Ans; unsigned long long pw[MAXN],Hash[MAXN]; unsigned long long Get(int l,int r){return Hash[r]-Hash[l-1]*pw[r-l+1];} int main(){ freopen("string.in","r",stdin); freopen("string.out","w",stdout); pw[0]=1; for(int i=1;i<MAXN;i++) pw[i]=pw[i-1]*27; cas=read(); while(cas--){ Ans=0; memset(Num,0,sizeof(Num)),res=0;memset(pre,0,sizeof(pre));memset(SS,0,sizeof(SS)); scanf("%s",str+1); N=strlen(str+1); for(int i=N;i>=1;i--){ Num[str[i]-'a']++; if(Num[str[i]-'a']&1) res++; else res--; suf[i]=res;//i-n F(str) str }memset(Num,0,sizeof(Num));res=0; for(int i=1;i<=N;i++){ Num[str[i]-'a']++; Hash[i]=Hash[i-1]*27ull+str[i]-'a'; if(Num[str[i]-'a']&1) res++; else res--; pre[i]=res; } for(int i=2;i<=N-1;i++){//A+B=i unsigned long long Sum=Get(1,i); int ps=pre[i-1];for(int j=ps;j<26;j++) SS[j]++; for(int j=1;j+i-1<N;j+=i){ if(Get(j,j+i-1)!=Sum) break; Ans+=SS[suf[j+i]]; } }printf("%lld\n",Ans); } return 0; }
下面是线性做法:
考虑利用 $kmp$ 判断是否为 $(AB)^i$,可以发现是只要考虑当前位置以及长度。
对于 $(AB)^i$ 与 $(AB)^{i+2}$ ,可以发现他们所对应的 $C$ 是相同的。
则我们对于 $i$ 的奇偶分类讨论,而对于 $(AB)$ 的长度差为 $1$ 的,$C$ 的差也只能为 $1$ ,所以直接通过桶指针扫一遍即可。
所以现在唯一的问题是如何给定 $(AB)$ ,如何求最大的 $i$ 使得前缀为 $(AB)^i$ ,二分 $kmp$ 即可。
时间复杂度 $O(\sum \log_2{\dfrac{n}{i}}+n)=O(n)$ 。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<vector> #include<queue> #define LL long long #define pb push_back #define mp make_pair #define fi first #define se second using namespace std; inline int read(){ int f=1,ans=0; char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int MAXN=1048581; char str[MAXN]; int N,cas,suf[MAXN],nex[MAXN],Num[27],res,S[27],pre[MAXN],real1,ps1,now1,now2,real2,ps2; LL Ans; int main(){ freopen("string.in","r",stdin); freopen("string.out","w",stdout); cas=read(); while(cas--){ Ans=0; memset(Num,0,sizeof(Num)),res=0;memset(pre,0,sizeof(pre)); scanf("%s",str+1); N=strlen(str+1); int p=0; for(int i=2;i<=N;i++){ while(str[p+1]!=str[i]&&p) p=nex[p]; if(str[p+1]==str[i]) nex[i]=p+1,++p; else nex[i]=0; } for(int i=N;i>=1;i--){Num[str[i]-'a']++;if(Num[str[i]-'a']&1) res++; else res--;suf[i]=res;} memset(Num,0,sizeof(Num));res=0;for(int i=1;i<=N;i++){Num[str[i]-'a']++;if(Num[str[i]-'a']&1) res++; else res--;pre[i]=res;} real1=real2=ps1=ps2=0;memset(Num,0,sizeof(Num)); for(int i=2;i<=N-1;i++){ int l=2,r=(N/i),res=1; if(!(N%i)) r--; if(pre[i-1]<=ps1) real1++; Num[pre[i-1]]++; if(pre[i-1]<=ps2) real2++; while(l<=r){ int mid=(l+r)>>1,pos=mid*i; if(!(i%(pos-nex[pos]))) res=mid,l=mid+1; else r=mid-1; }now1=((res+1)/2),now2=res-now1; while(ps1<suf[i+1]) real1+=Num[ps1+1],ps1++; while(ps1>suf[i+1]) real1-=Num[ps1],ps1--; Ans+=now1*real1; if(i+i+1<=N){while(ps2<suf[i+i+1]) real2+=Num[ps2+1],ps2++; while(ps2>suf[i+i+1]) real2-=Num[ps2],ps2--;Ans+=now2*real2;} }printf("%lld\n",Ans); } return 0; }/* nnrnnr */
C
$40$ 分的做法是 $swap$ 柱内的两个元素,其代价是 $4m$ ,然后就走上不归路了......
设最后 $i$ 号柱子上是 $i$ 颜色的球。我们发现单体调整太蠢了,故考虑当 $n=2$ 时有什么整体调整的做法。
设 $s$ 表示 $1$ 号柱子上球的个数,我们可以通过 $O(5m-s)$ 的代价将 $1$ 个柱子都是 $1$ 颜色,一个柱子全为 $2$ 颜色。具体的实现方式参考 Dzhao 。
而对于 $n>2$ 的情况,对颜色分治解决即可。上界为 $O(5mn\log n)$ ,可以通过此题。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<vector> #include<queue> #define pb push_back #define mp make_pair #define fi first #define se second #define pii pair<int,int> using namespace std; inline int read(){ int f=1,ans=0; char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int MAXN=411; int N,M,A[MAXN][MAXN],tot,Sta[MAXN]; pii Ans[820011]; void swap(int X1,int Y1,int X2,int Y2){ if(Y1>=Y2) swap(X1,X2),swap(Y1,Y2); //push X2 to XX for(int i=1;i<=Y2;i++) Ans[++tot].fi=X2,Ans[tot].se=N+1;//printf("%d %d\n",X2,N+1); //push X1 to X2 for(int i=1;i<=Y1;i++) Ans[++tot].fi=X1,Ans[tot].se=X2;//printf("%d %d\n",X1,X2); //d to x1 Ans[++tot].fi=N+1,Ans[tot].se=X1;//printf("%d %d\n",N+1,X1); //c to XX Ans[++tot].fi=X2,Ans[tot].se=N+1;//printf("%d %d\n",X2,N+1); // X1 to X1 for(int i=1;i<=Y1-1;i++) Ans[++tot].fi=X2,Ans[tot].se=X1;//printf("%d %d\n",X2,X1); // X2 to X2 for(int i=1;i<=Y2;i++) Ans[++tot].fi=N+1,Ans[tot].se=X2;//printf("%d %d\n",N+1,X2); swap(A[X1][Y1],A[X2][Y2]); return; } int Num[MAXN],Cnt,p[MAXN],ss[MAXN]; struct node{int col,cnt,id;} F[MAXN*MAXN]; bool cmp(node x1,node x2){return x1.cnt>x2.cnt;} int main(){ N=read(),M=read(); for(int i=1;i<=N;i++) for(int j=M;j>=1;j--) A[i][j]=read(); for(int i=1;i<=N;i++){ memset(Num,0,sizeof(Num)); for(int j=1;j<=M;j++) Num[A[i][j]]++; for(int j=1;j<=N;j++){ ++Cnt; F[Cnt].id=i,F[Cnt].col=j,F[Cnt].cnt=Num[j]; } }sort(F+1,F+Cnt+1,cmp); for(int i=1;i<=Cnt;i++){ if(!p[F[i].col]&&!ss[F[i].id]){ ss[F[i].id]=1; p[F[i].col]=F[i].id; } } for(int col=1;col<=N;col++){ Sta[0]=0;int ps=p[col]; for(int i=1;i<=M;i++) if(A[ps][i]!=col) Sta[++Sta[0]]=i; for(int i=1;i<=N;i++){ if(i==ps) continue; for(int j=1;j<=M;j++){ if(A[i][j]==col) swap(i,j,ps,Sta[Sta[0]]),Sta[0]--; } } } printf("%d\n",tot); for(int i=1;i<=tot;i++) printf("%d %d\n",Ans[i].fi,Ans[i].se); return 0; }
#include<iostream> #include<cstring> #include<cstdio> #include<climits> #include<algorithm> #include<queue> #include<vector> #define pii pair<int,int> #define mp make_pair #define pb push_back #define fi first #define se second using namespace std; inline int read(){ int f=1,ans=0; char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int MAXN=52; const int MAXM=411; pii Ans[820001]; int N,M,A[MAXN][MAXM],cnt; bool f[MAXN]; void move(int x,int y){Ans[++cnt].fi=x,Ans[cnt].se=y;return;} int sta[MAXM]; void print(int x){for(int i=1;i<=M;i++) printf("%d ",A[x][i]);printf("\n");return;} void solve(int l,int r){ if(l==r) return;int mid=(l+r)>>1; for(int i=l;i<=mid;i++){ f[i]=1; for(int j=1;j<=M;j++) f[i]&=(A[i][j]<=mid); } for(int i=mid+1;i<=r;i++){ f[i]=1; for(int j=1;j<=M;j++) f[i]&=(A[i][j]>mid); } for(int i=l;i<=mid;i++){ for(int j=mid+1;j<=r;j++){ if(f[i]||f[j]) continue;//<=mid 1 int tot1=0,tot2=0; for(int k=1;k<=M;k++) tot1+=(A[i][k]<=mid); for(int k=1;k<=M;k++) tot2+=(A[j][k]>mid); if(tot1>=tot2){ int now1=1,now2=1; for(int k=1;k<=tot1;k++) move(j,N+1),sta[++sta[0]]=A[j][now2],now2++; for(int k=1;k<=M;k++){ if(A[i][now1]<=mid){move(i,j);A[j][--now2]=A[i][now1],now1++;} else{ move(i,N+1);sta[++sta[0]]=A[i][now1],now1++; } } for(int k=1;k<=tot1;k++){move(j,i);A[i][--now1]=A[j][now2],now2++;} for(int k=1;k<=M-tot1;k++){move(N+1,i),A[i][--now1]=sta[sta[0]],sta[0]--;} for(int k=1;k<=M-tot1;k++){move(j,N+1);sta[++sta[0]]=A[j][now2],now2++;} for(int k=1;k<=M-tot1;k++){move(i,j);A[j][--now2]=A[i][now1],now1++;} for(int k=1;k<=M;k++){ if(sta[sta[0]]<=mid&&now1!=1){move(N+1,i);A[i][--now1]=sta[sta[0]],sta[0]--;} else{move(N+1,j);A[j][--now2]=sta[sta[0]],sta[0]--;} } f[i]=1;continue; }else{ int now1=1,now2=1; for(int k=1;k<=tot2;k++) move(i,N+1),sta[++sta[0]]=A[i][now1],now1++; for(int k=1;k<=M;k++){ if(A[j][now2]>mid){move(j,i),A[i][--now1]=A[j][now2],now2++;} else{ move(j,N+1);sta[++sta[0]]=A[j][now2],now2++; } } for(int k=1;k<=tot2;k++){move(i,j);A[j][--now2]=A[i][now1],now1++;} for(int k=1;k<=M-tot2;k++){move(N+1,j);A[j][--now2]=sta[sta[0]];sta[0]--;} for(int k=1;k<=M-tot2;k++){move(i,N+1);sta[++sta[0]]=A[i][now1],now1++;} for(int k=1;k<=M-tot2;k++){move(j,i);A[i][--now1]=A[j][now2],now2++;} for(int k=1;k<=M;k++){ if(sta[sta[0]]>mid&&now2!=1){move(N+1,j),A[j][--now2]=sta[sta[0]],sta[0]--;} else{move(N+1,i);A[i][--now1]=sta[sta[0]],sta[0]--;} }f[j]=1;continue; } } }solve(l,mid),solve(mid+1,r); return; } int main(){ N=read(),M=read(); for(int i=1;i<=N;i++) for(int j=M;j>=1;j--) A[i][j]=read(); solve(1,N); printf("%d\n",cnt); for(int i=1;i<=cnt;i++) printf("%d %d\n",Ans[i].fi,Ans[i].se); return 0; }/* 2 3 1 1 2 2 1 2 */
D
写了两个包,结果一个包没有取 $min$ ,一个包数组应该开 $3$ ,开成了 $2$ ,送的 $20$ 分也没写,$zbl$。
对于前 $80$ 分做法是按维独立后计算 $Ans_{i,j}$ 表示从第 $i$ 维的第 $j$ 个走出去的最小步数,排序计算即可。
正解考虑换贡献,先跑 $2$ 天得到:
$a_j$ 表示 $j$ 维在 $1$ 天后的空间,$del_j$ 表示在第 $2$ 天之后每天会有 $del_j$ 个在第 $j$ 维失效,$l_{i,j}$ 表示在第 $i$ 步第 $j$ 维之前的最大左偏移量,同理可得 $r_{i,j}$ 。
所以只需要计算一天后的答案。
考虑有多少个位置可以在第 $t+2$ 天的第 $i$ 步没有走到终点的贡献,可以表示为
$$
\prod_{j=1}^k (a_j-t\times del_j-l_{i,j}-r_{i,j})
$$
设 $len_{i,j}=a_j-l_{i,j}-r_{i,j}$ ,则上式可以表示为
$$
\prod_{j=1}^k len_{i,j}-t\times del_j
$$
可以发现上式是对于 $t$ 的 $k$ 次多项式,设其为 $f(t)$ ,而 $t$ 的取值范围为 $[0,\dfrac{len_{i,j}}{del_j}]$ 。
而对于步数为 $i$ 的$f$ 值之和为 $\sum_{t=0}^{tmax} f(t)$ ,而 $f(t)=\sum_{j=0}^k a_jt^j$ ,代入可得
$$
\sum_{t=0}^{tmax}f(t)=\sum_{t=0}^{tmax} \sum_{j=0}^k a_jt^j=\sum_{j=0}^k a_j\sum_{t=0}^{tmax} t^j
$$
对于后半段是自然数幂之和,可以通过构造 $j+1$ 次多项式连续性函数的拉格朗日插值 $O(j)$ 单次计算。
则我们现在已经可以通过 $O(k^2)$ 的时间计算一次 $i$ 步的答案。
我们对于 $i$ 到 $i+1$ 不能直接修改 $f(t)$ ,否则时间复杂度为 $O(n^2)$ 。
而 $i$ 到 $i+1$ 只会有 $1$ 维的 $len$ 发生改变,则我们暴力写多项式除法与乘法即可解决。
而对于 $tmax$ 也动态维护即可,时间复杂度 $O(nk^2)$ 。
代码鸽了,以后再补。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<vector> #include<queue> #include<map> #define int long long #define mod 1000000007 #define pb push_back #define mp make_pair #define fi first #define se second #define pii pair<int,int> using namespace std; inline int read(){ int f=1,ans=0; char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int MAXN=1e5+11; const int MAXK=6; int C[MAXN],D[MAXN],N,K,W[MAXK],X[MAXK],Up[MAXK],Down[MAXK],Del[MAXK]; map<pii,int> M; namespace subtask1{ int Ans[MAXK][MAXN],p[MAXK],res; void calc(){ int Minn=Ans[1][p[1]]; for(int i=2;i<=K;i++) Minn=min(Minn,Ans[i][p[i]]); res+=Minn;res%=mod;return; } void dfs(int u){ if(u==K+1){calc();return;} for(int i=1;i<=W[u];i++) p[u]=i,dfs(u+1); } void Main(){ memset(Ans,127/3,sizeof(Ans)); for(int i=1;i<=K;i++){ for(int j=1;j<1-Down[i];j++){ if(j>=1&&j<=W[i]){ Ans[i][j]=M[mp(i,-j)]; } } for(int j=W[i]-Up[i]+1;j<=W[i];j++){ if(j>=1&&j<=W[i]){ Ans[i][j]=min(Ans[i][j],M[mp(i,W[i]-j+1)]); } } } for(int i=1;i<=K;i++){ int L=-Down[i]+1,R=W[i]-Up[i]; if(!Del[i]) continue; if(Del[i]<0){ for(int j=L;j<=R;j++) if(j>=1&&j<=W[i]) Ans[i][j]=Ans[i][j+Del[i]]+N; }else{ for(int j=R;j>=L;j--) if(j>=1&&j<=W[i]) Ans[i][j]=Ans[i][j+Del[i]]+N; } } /*for(int i=1;i<=K;i++) printf("%lld %lld %lld\n",Down[i],Up[i],Del[i]); printf("==============\n"); for(int i=1;i<=K;i++){ for(int j=1;j<=W[i];j++) printf("%lld ",Ans[i][j]);printf("\n"); } exit(0);*/ dfs(1); printf("%lld\n",res); exit(0); } }bool ff=1; namespace subtask2{ int Ans[3][1000011],S[3][1000011],res; void Main(){ memset(Ans,127/3,sizeof(Ans)); for(int i=1;i<=K;i++){ for(int j=1;j<1-Down[i];j++){ if(j>=1&&j<=W[i]){ Ans[i][j]=M[mp(i,-j)]; } } for(int j=W[i]-Up[i]+1;j<=W[i];j++){ if(j>=1&&j<=W[i]){Ans[i][j]=M[mp(i,W[i]-j+1)];} } } for(int i=1;i<=K;i++){ int L=-Down[i]+1,R=W[i]-Up[i]; if(!Del[i]) continue; if(Del[i]<0){ for(int j=L;j<=R;j++) if(j>=1&&j<=W[i]) Ans[i][j]=Ans[i][j+Del[i]]+N; }else{ for(int j=R;j>=L;j--) if(j>=1&&j<=W[i]) Ans[i][j]=Ans[i][j+Del[i]]+N; } } //for(int i=1;i<=K;i++) printf("%lld %lld %lld\n",Down[i],Up[i],Del[i]); //for(int i=1;i<=W[1];i++) printf("%lld ",Ans[1][i]);printf("\n"); //for(int i=1;i<=W[2];i++) printf("%lld ",Ans[2][i]);printf("\n"); //exit(0); sort(Ans[1]+1,Ans[1]+W[1]+1),sort(Ans[2]+1,Ans[2]+W[2]+1); for(int i=1;i<=W[1];i++) S[1][i]=S[1][i-1]+Ans[1][i],S[1][i]%=mod; for(int i=1;i<=W[2];i++) S[2][i]=S[2][i-1]+Ans[2][i],S[2][i]%=mod; for(int i=1;i<=W[1];i++){ int l=1,r=W[2],pp=-1; while(l<=r){ int mid=(l+r)>>1; if(Ans[2][mid]<=Ans[1][i]) pp=mid,l=mid+1; else r=mid-1; }if(pp!=-1) res+=S[2][pp],res%=mod; } for(int i=1;i<=W[2];i++){ int l=1,r=W[1],pp=-1; while(l<=r){ int mid=(l+r)>>1; if(Ans[1][mid]<Ans[2][i]) pp=mid,l=mid+1; else r=mid-1; }if(pp!=-1) res+=S[1][pp],res%=mod; }printf("%lld\n",res); exit(0); } } signed main(){ freopen("walk.in","r",stdin); freopen("walk.out","w",stdout); N=read(),K=read(); if(K>=6||N>MAXN){printf("-1\n");return 0;} for(int i=1;i<=K;i++) W[i]=read(),ff&=(W[i]<=10); for(int i=1;i<=N;i++) C[i]=read(),D[i]=read(); for(int i=1;i<=N;i++){ X[C[i]]+=D[i]; if(!M[mp(C[i],X[C[i]])]){ M[mp(C[i],X[C[i]])]=i; //cerr<<i<<"==="<<C[i]<<"==="<<X[C[i]]<<endl; } Up[C[i]]=max(Up[C[i]],X[C[i]]); Down[C[i]]=min(Down[C[i]],X[C[i]]); } for(int i=1;i<=K;i++) Del[i]=X[i]; int cnt=0; for(int i=1;i<=K;i++) if(!Del[i]&&Down[i]+1<=W[i]-Up[i]) cnt++; if(cnt==K){printf("-1\n");return 0;} if((K<=5&&ff)||K==1) subtask1::Main(); if(K==2) subtask2::Main(); printf("-1\n"); return 0; }/* 3 2 3 3 1 1 2 -1 1 1 */