• QZS8.17


    T1

    啊?60改成20???啊啊啊

    60

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int N=1000005;
    const int mod=1000000007;
    int n,p[N];
    long long sum[N],ans,dp[N];
    int main() {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)  
            scanf("%d",&p[i]);
        dp[1]=2;sum[1]=2;
        for(int i=2;i<=n;i++) {
            dp[i]=(2+sum[i-1]-sum[p[i]-1])%mod;
            sum[i]=(dp[i]+sum[i-1])%mod;
        }
        for(int i=1;i<=n;i++)
            ans=(ans+dp[i])%mod;
        printf("%lld
    ",ans);
        return 0;
    }
    

    想假了???

    正解

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int N=1000005;
    const int mod=1000000007;
    int n,p[N];
    long long ans,dp[N];
    int main() {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)  
            scanf("%d",&p[i]);
        for(int i=1;i<=n;i++)
            dp[i+1]=(dp[i]+dp[i]-dp[p[i]]+2)%mod;
        for(int i=1;i<=n;i++)
            ans=(ans+dp[i])%mod;
        printf("%lld
    ",(dp[n+1]+mod)%mod);
        return 0;
    }
    

    T2

    赤裸裸的暴力40分

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const long long mod=4294967296;
    int n,m;
    char op,z,ch,s[50005];
    long long query(int l,int r) {
        long long res=0;
        for(int i=l;i<=r;i++) {
            if(s[i]=='0') {
                for(int j=i+1;j<=r;j++) {
                    if(s[j]=='w') {
                        for(int k=j+1;k<=r;k++)
                            if(s[k]=='0') res++;
                    }
                }
            }
        }
        return res;
    }
    int main() {
        scanf("%d%d",&n,&m);
        scanf("%s",s+1);
        for(int i=1,x,y;i<=m;i++) {
            cin>>op;scanf("%d",&x);
            if(op=='A') {
                cin>>z;
                s[x]=z;
            } else if(op=='B') {
                scanf("%d",&y);cin>>z;
                for(int j=x;j<=y;j++)
                    s[j]=z;
            } else {
                scanf("%d",&y);
                long long ans=0;
                int L=0;
                for(int j=x;j<=y;j++) {
                    if(s[j]=='(') {
                    	L=j;
                    	for(int k=j+1;k<=y;k++) 
    	                    if(s[k]==')') 
    	                        ans+=query(L,k); 
    				}
                }
                printf("%lld
    ",ans%mod);
            }
        }
        return 0;
    }
    

    线段树维护字符串+合并

    思路大致对的,but代码只有60分

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    #define ls (p<<1)
    #define rs (p<<1|1)
    const long long mod=4294967296;
    #define int long long
    const int N=200005;
    int n,m;
    char op,z,ch,s[N];
    int root,len[N];
    char tag[N];
    int f[N][5][5];
    int ans[5][5],tmp[5][5];
    void merge(int g1[5][5],int g2[5][5],int g[5][5]) {
        for(int i=0;i<=4;i++)
            for(int j=i;j<=4;j++) {
                g[i][j]=(g1[i][j]+g2[i][j])%mod;
                for(int k=i;k<j;k++)
                    g[i][j]=(g[i][j]+g1[i][k]*g2[k+1][j]%mod)%mod;
            }
    }
    void build(int l,int r,int p) {
        len[p]=r-l+1;
        if(l==r) {
            if(s[l]=='(') f[p][0][0]=1;
            else if(s[l]=='0') f[p][1][1]=f[p][3][3]=1;
            else if(s[l]=='w') f[p][2][2]=1;
            else if(s[l]==')') f[p][4][4]=1;
            return;
        }
        int mid=(l+r)>>1;
        build(l,mid,ls);
        build(mid+1,r,rs);
        merge(f[ls],f[rs],f[p]);
    }
    void pushdown(int p) {
        if(!tag[p]) return;
        tag[ls]=tag[rs]=tag[p];
        memset(f[p],0,sizeof(f[p]));
        if(tag[p]=='(') f[p][0][0]=len[p];
        else if(tag[p]=='0') f[p][1][1]=f[p][3][3]=len[p];
        else if(tag[p]=='w') f[p][2][2]=len[p];
        else if(tag[p]==')') f[p][4][4]=len[p];
        tag[p]=0;
    }
    void modify(int l,int r,int L,int R,int p) {
        if(L<=l&&r<=R) {
            tag[p]=z;
            pushdown(p);
            return;
        }
        pushdown(ls);pushdown(rs);
        int mid=(l+r)>>1;
        if(L<=mid) modify(l,mid,L,R,ls);
        if(R>mid) modify(mid+1,r,L,R,rs);
        merge(f[ls],f[rs],f[p]);
    }
    void query(int l,int r,int L,int R,int p) {
        if(L<=l&&r<=R) {
            merge(ans,f[p],tmp);
            memcpy(ans,tmp,sizeof(tmp));
            return;
        }
        pushdown(ls);pushdown(rs);
        int mid=(l+r)>>1;
        if(L<=mid) query(l,mid,L,R,ls);
        if(R>mid) query(mid+1,r,L,R,rs);   
    }
    signed main() {
        scanf("%d%d",&n,&m);
        scanf("%s",s+1);
        build(1,n,1);
        for(int i=1,x,y;i<=m;i++) {
            cin>>op;
            scanf("%d",&x);
            if(op=='A') {
                cin>>z;
                modify(1,n,x,x,1);
            } else if(op=='B') {
                scanf("%d",&y);cin>>z;
                modify(1,n,x,y,1);
            } else {
                scanf("%d",&y);
                memset(ans,0,sizeof(ans));
                query(1,n,x,y,1);
                printf("%lld
    ",ans[0][4]%mod);
            }
        }
        return 0;
    }
    

    T3

    https://www.luogu.com.cn/blog/52243/ti-xie-qi-zhi-shu-day1t3-tiramisu

    首先01序列有可差分性质

    运用差分(异或意义下)可以将区间取反 降到 (O(1))

    观察差分序列,我们暴力中每次会把距离为 k 的两个点取反。

    问题转化成在这样的差分序列中,每次将距离为 k 的两个点取反,需要的最小操作次数。

    举个栗子:

    原序列:0100011010
    询问[7, 9]
    提取+前导和后导零 0 101 0
    差分:01111
    

    这里具体说一下加前导和后导零的必要

    前导零比较好说,一是为了保证差分序列长度=原序列长度

    二是如果提取出的序列为 101 ,我们最后的目标是把这段都变成0, 如果加的是前导1,那么这差分序列就成了010,显然与原序列不符。

    后导零呢再举个栗子

    提取 011 ,设k=2,显然我们取一次即可

    but 他的差分序列是 (0)010 ,不加后导零是搞不出那一对的

    加了之后 是 (0)010(1) 我们就可以快乐取反了

    判断有解

    注意到,由于每次取反的距离为k,所以只有在编号模 k 值相同的位置中,(即处于%k同余系相同的位置)1 的个数为偶数个,问题有解

    可以用哈希 O(1) 判断是否有解:

    对编号模 k 值相同的位置赋一个 hash 值,然后对所有 1 做前缀异或和。

    因为异或的性质,某个 hash 值有偶数个,异或起来为 0。

    那么提取区间异或和即可判断是否有解。

    统计答案

    对于询问区间[L,R] ,由上面这个(0)010(1)例子,我们可以发现其实询问的是差分数组的[L,R+1] ,

    现在要计算最小操作次数,易得我们需要将编号模 k 值相同的位置中,所有的 1 相邻两两配对。

    答案就是每对位置差除以 k。

    我们还是对这些答案做前缀和,以便 O(1)查询。

    需要注意的是,两两配对的点中,做前缀和的话,如果有偶数个点那么恰好为答案;如果有奇数个点,要考虑到两个前缀和做差形成偶数个点的情况。

    刚才的前导零和后导零是我们自己把原序列那个位置强制假设为0,如果其实际位置是1 呢?这显然对答案统计是有影响的。

    具体的,我们先不考虑 L , R+1

    答案区间转化为 [L+1,R]

    ans = sum[R]-sum[L]

    然后考虑强制假设的影响,我们可以记录个nxt[i] , 表示 i 之前包括 i 在内的%k同余系下相同的位置 产生的ans,bef [i] , 表示 i 之前不包括 i 在内的%k同余系下相同的位置 产生的ans,然后就判断如果 R是1 ,则证明 R+1 一定是1,( 后导0 ^ 1 = 1),然后处理其贡献

    //假设我们之前的前缀和是p3 - p2 + p1,现在我们要变成p4 - p3 + p2 - p1
    // 所以应该先把p3 - p2 + p1 ①减去
    // 之后需要再加上p4 - (p3 - p2 + p1) ②
    // ①+②= r + 1 (p4)- 2 * p3 - p2 +p1
    // 而bef数组就是存的"p3 - p2 + p1"的值
    if(c[r] == '1')
        res += r + 1 - 2 * bef[r + 1];
    if(c[l] == '1')
        res -= l - 2 * nex[l];
    

    At last

    代码

    #include <ctime>
    #include <cstdio>
    #include <cctype>
    #include <cstdlib>
    #include <iostream>
    using namespace std;
    #define int long long
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    const int N = 2e6 + 5;
    int n,m,k,l,r,res;
    char c[N];
    int dif[N],has[N],pre[N];
    int sum[N],b[N],bef[N],nxt[N];
    signed main() {
        srand(time(0));
        n=read();k=read();m=read();
        scanf("%s",c+1);
        c[0]='0',c[n+1]='0';
        for(int i=1;i<=n+1;i++)//差分
            dif[i]=(c[i-1]=='1')^(c[i]=='1');
        for(int i=0;i<k;i++) //k的余数域hash值
            has[i]=rand()*rand()+rand();
        for(int i=1;i<=n+1;i++) //差分前缀和hash——一会判奇偶
            if(dif[i]) pre[i]=pre[i-1]^has[i%k];
            else pre[i]=pre[i-1];
        for(int i=1;i<=n+1;i++) {
            sum[i]=sum[i-1];//所有位置的前缀答案
            bef[i]=b[i%k];//b[]模k值相同的位置的前缀答案
            if(dif[i]) {
                sum[i]-=b[i%k];
                b[i%k]=i-b[i%k];
                sum[i]+=b[i%k];
            // 如果有偶数个点,b[i%k]值为两两距离差除以k,即答案(/k最后统一除)
            // 如果有奇数个点,b[i%k]值为 i-原b[i%k],即该位置减去之前的答案 例:pre=pos2-pos1,now=pos3-pre=pos3-pos2+pos1
            }
            nxt[i]=b[i%k];
        }
        while(m--) {
            l=read();r=read();
            if(pre[l]^pre[r]^((c[l]!='0')*has[l%k]^((c[r]!='0')*has[(r+1)%k]))) {
                puts("-1");continue;
            }
            res=sum[r]-sum[l];//暂不考虑r + 1 , l 
            // 所以应该先把p3 - p2 + p1 ①减去
            // 之后需要再加上p4 - (p3 - p2 + p1) ②
            // ①+②= r + 1 (p4)- 2 * p3 - p2 +p1
            // 而bef数组就是存的"p3 - p2 + p1"的值        
            if(c[r]=='1') 
                res+=r+1-2*bef[r+1];
            if(c[l]=='1')
                res-=l-2*nxt[l];
            printf("%lld
    ",res/k);
        }
        return 0;
    }
    
  • 相关阅读:
    [SAP ABAP开发技术总结]OLE
    [SAP ABAP开发技术总结]ABAP读写、解析XML文件
    [SAP ABAP开发技术总结]FTP到文件服务器,服务器上文件读写
    [SAP ABAP开发技术总结]Function远程、同步、异步调用
    [SAP ABAP开发技术总结]采购、销售、生产简单业务流程
    [SAP ABAP开发技术总结]IDoc
    [SAP ABAP开发技术总结]BAPI调用
    [SAP ABAP开发技术总结]业务对象和BAPI
    [SAP ABAP开发技术总结]增强Enhancement
    [SAP ABAP开发技术总结]SD销售订单定价过程
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13544341.html
Copyright © 2020-2023  润新知