• 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
    ",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("
    ");}
        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
    ",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
    ",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(5mnlog 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
    ",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
    ",X1,X2);
        //d to x1
        Ans[++tot].fi=N+1,Ans[tot].se=X1;//printf("%d %d
    ",N+1,X1);
        //c to XX
        Ans[++tot].fi=X2,Ans[tot].se=N+1;//printf("%d %d
    ",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
    ",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+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
    ",tot);
        for(int i=1;i<=tot;i++) printf("%d %d
    ",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("
    ");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
    ",cnt);
        for(int i=1;i<=cnt;i++) printf("%d %d
    ",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 imes 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 imes 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_jsum_{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
    ",Down[i],Up[i],Del[i]);
            printf("==============
    ");
            for(int i=1;i<=K;i++){
                for(int j=1;j<=W[i];j++) printf("%lld ",Ans[i][j]);printf("
    ");
            }
            exit(0);*/
            dfs(1);
            printf("%lld
    ",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
    ",Down[i],Up[i],Del[i]);
            //for(int i=1;i<=W[1];i++) printf("%lld ",Ans[1][i]);printf("
    ");
            //for(int i=1;i<=W[2];i++) printf("%lld ",Ans[2][i]);printf("
    ");
            //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
    ",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
    ");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
    ");return 0;}
        if((K<=5&&ff)||K==1) subtask1::Main();
        if(K==2) subtask2::Main();
        printf("-1
    "); return 0;
    }/*
    3 2
    3 3
    1 1
    2 -1
    1 1
    */
    改-考场代码
  • 相关阅读:
    4年Java程序员十面阿里终拿下offer,评级P6+年薪30-40w无股票
    真香警告!手绘172张图解HTTP协议+703页TCP/IP协议笔记
    Git官方和创始人都推荐的Git权威指南,广度深度和实战性史无前例
    阿里“教授”总结整理手写大型网站技术架构:核心原理与案例分析
    GitHub上120K Stars国内第一的Java多线程PDF到底有什么魅力?
    霸榜GitHub必读书籍:编写高质量代码改善Java程序员的151个建议
    GitHub上260K Stars的P8架构师纯手写的Java高并发编程详解
    LeetCode每日一题:802 找到最终安全状态
    LeetCode每日一题:662二叉树最大宽度
    Springboot之security框架 登录安全验证授权流程
  • 原文地址:https://www.cnblogs.com/si-rui-yang/p/14136747.html
Copyright © 2020-2023  润新知