zoukankan      html  css  js  c++  java
  • NOIP模拟测试20「周·任·飞」

    liu_runda出的题再次$\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%$

    题解

    题目中为什么反复强调简单路径,没有环

    没有环的图中点数-边数=联通块数

    前缀和维护边的前缀和,和点的前缀和,

    在维护边的前缀和不好维护转化为横着边前缀和,竖着边前缀和

    注意边的边界问题

    看边如何维护

    就拿我的举例

    你在当前为边且当前左面为边时置为1

    那么当你统计答案时

            ll bia=bianheng[x2][y2]-bianheng[x1-1][y2]-bianheng[x2][y1]+bianheng[x1-1][y1];

    思考我们统计答案时要把x2相连的边切断

    类似的,我们维护竖着的边时也要类似操作

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll int
    #define A 2101
    char s[A][A];
    ll vis[A][A],stax[4200000],stay[4200000],dian[A][A],bianheng[A][A],bianshu[A][A];
    ll cnt=0,n,m,q;
    const ll nowx[5]={0,0,0,1,-1};
    const ll nowy[5]={0,1,-1,0,0};
    void dfs(ll x,ll y,ll x1,ll y1,ll x2,ll y2){
        vis[x][y]=cnt;
    //    printf("x=%lld y=%lld vis=%lld
    ",x,y,vis[x][y]);
        for(ll i=1;i<=4;i++){
            ll xnow=x+nowx[i],ynow=y+nowy[i];
            if(xnow>x2||xnow<x1) continue;
            if(ynow>y2||ynow<y1) continue;
            if(s[xnow][ynow]-'0'==0) continue;
            if(vis[xnow][ynow]) continue;
            dfs(xnow,ynow,x1,y1,x2,y2);
        }
    }
    void bfs(ll x1,ll y1,ll x2,ll y2){
        cnt=0;
        for(ll i=x1;i<=x2;i++)
            for(ll j=y1;j<=y2;j++){
                if(s[i][j]=='1'&&!vis[i][j]){
                    ++cnt;
                    dfs(i,j,x1,y1,x2,y2);
                }
            }
        for(ll i=x1;i<=x2;i++)
            for(ll j=y1;j<=y2;j++){
                vis[i][j]=0;
            }
        printf("%d
    ",cnt);
    }
    int main(){
        scanf("%d%d%d",&n,&m,&q);
        for(ll i=1;i<=n;i++){
            scanf("%s",s[i]+1);
        }
    //    memset()
        for(ll i=1;i<=n;i++)
            for(ll j=1;j<=m;j++){
                if(s[i][j]=='1'&&s[i][j-1]=='1'){
                    bianheng[i][j]++;
                }
                if(s[i][j]=='1'&&s[i-1][j]=='1'){
                    bianshu[i][j]++;
                }
                if(s[i][j]=='1'){
                    dian[i][j]++;
                }
            }
        for(ll i=1;i<=n;i++)
            for(ll j=1;j<=m;j++){
            bianheng[i][j]=bianheng[i][j]+bianheng[i-1][j]+bianheng[i][j-1]-bianheng[i-1][j-1];
            bianshu[i][j]=bianshu[i][j]+bianshu[i-1][j]+bianshu[i][j-1]-bianshu[i-1][j-1];
            dian[i][j]=dian[i][j]+dian[i-1][j]+dian[i][j-1]-dian[i-1][j-1];
        }
    //    for(ll i=1;i<=n;i++,puts(""))
    //        for(ll j=1;j<=m;j++){
    //            printf("bian=%d ",bianheng[i][j]);
    //        }
        for(ll i=1,x1,x2,y1,y2;i<=q;i++){
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            ll bia=bianheng[x2][y2]-bianheng[x1-1][y2]-bianheng[x2][y1]+bianheng[x1-1][y1];
    //        printf("%d %d %d %d bia=%d
    ",bianheng[x2][y2],bianheng[x1-1][y2],bianheng[x2][y1],bianheng[x1-1][y1-1],bia);
            bia+=bianshu[x2][y2]-bianshu[x1][y2]-bianshu[x2][y1-1]+bianshu[x1][y1-1];
    //        printf("%d %d %d %d        bia=%d
    ",bianshu[x2][y2],bianshu[x1][y2],bianshu[x2][y1-1],bianshu[x1-1][y1-1],bia);
            ll dia=dian[x2][y2]-dian[x1-1][y2]-dian[x2][y1-1]+dian[x1-1][y1-1];
            printf("%d
    ",dia-bia);
        }
    }

    题解

    其实就是求逆序对,然而逆序对是$n*log$的并不能过,思考优化

    我们发现其实它给了多段等差数列,

    先看所有等差数列都是完整的情况

    我们在同一段等差数列上可以由$x[i-1]$推到$x[i]$思考我们找的是比当前大的个数,$x[i]=x[i-1]+a$所有之前等差数列贡献都要减一

    那么设之前贡献$tmp$得到当前贡献$tmp-cnt(等差数列个数)$

    那么我们思考$<a$(即等差数列首项)怎么维护,我们拿一个树状数组维护$<a$的所有值

    假设当前值为$x$那么逆序对数就是$i-sum(x)-1$

    然后我们考虑第一段不是完整的

    假设当前$x$转移到$x2$中$x,x2$都比$begin$小那么等差数列上所有小于$begin$贡献都要减一(头一段上没有处于$x$--$x2$数不能转移)

    若当前已经比$begin$大了把它当成一个正常等差数列

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define A 111111
    ll c[A];
    ll tus,n,a,mod,now,cnt=0,ans=0,last,tmp;
    void add(ll x,ll u){
        for(ll i=x;i<=a;i+=i&-i)
            c[i]+=u;
    }
    ll sum(ll x){
        ll ans=0;
        for(ll i=x;i>=1;i-=i&-i)
            ans+=c[i];
        return ans;
    }
    int main(){
        scanf("%lld%lld%lld%lld",&n,&tus,&a,&mod);
        ll now=tus;
        if(tus<=a){
            add(tus+1,1);
        }
        for(ll i=2;i<=n;i++){
            now=(a+now)%mod;
            if(now<a){
                tmp=i-sum(now+1)-1;
                cnt++;
                add(now+1,1);
            }
            else{
                tmp-=cnt;
                if(now<tus) tmp++;
            }
            ans+=tmp;
        }
        printf("%lld
    ",ans);
    }
  • 相关阅读:
    希尔排序
    插入排序
    Unity创建一个简易的弹簧(弹动)效果
    看到个美到爆的菜单,忍不住扒下来~
    用avalon实现一个完整的todomvc(带router)
    页面动态加入<script>标签并执行代码
    一个简单粗暴的前后端分离方案
    常用的HTML5、CSS3新特性能力检测写法
    犀利的background-clip:text,实现K歌字幕效果
    用canvas开发H5游戏小记
  • 原文地址:https://www.cnblogs.com/znsbc-13/p/11366198.html
Copyright © 2011-2022 走看看