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
*/
View Code

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
*/
改-考场代码

 

posted @ 2020-12-15 16:59  siruiyang_sry  阅读(202)  评论(0编辑  收藏  举报