• 21杭电多校第三场


    A

    离谱平衡树题 咕

    B

    好像更离谱的结论题

    C

    (ans_i)表示以(a)串的(i)为起始匹配位置的失配数

    (ans_i=sumlimits_{j=0}^{m-1} [b_j eq a_{i+j}]),将(b)串翻转,即有(ans_i=sumlimits_{j=0}^{m-1} [b_{m-1-j} eq a_{i+j}])成为一个卷积形式

    可以枚举(b_j)的取值进行(0/1)赋值来卷积得到(ans_i)

    最后将(cnt[ans_i]++),输出(cnt)的前缀和

    #include<bits/stdc++.h>
    #define inf 2139062143
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    #define MAXN 200100
    #define MOD 998244353
    #define Fill(a,x) memset(a,x,sizeof(a))
    #define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
    #define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
    #define ren for(int i=fst[x];i;i=nxt[i])
    #define pls(a,b) (a+b)%MOD
    #define mns(a,b) (a-b+MOD)%MOD
    #define mul(a,b) (1LL*(a)*(b))%MOD
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    using namespace std;
    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 x*f;
    }
    const db pi=acos(-1);
    int n,m,rev[MAXN<<2],sum,ans[MAXN<<2],cnt[MAXN];
    char s1[MAXN],s2[MAXN];
    struct Cd{db x,y;Cd(db X=0,db Y=0){x=X,y=Y;};};
    Cd operator + (Cd a,Cd b) {return (Cd){a.x+b.x,a.y+b.y};}
    Cd operator - (Cd a,Cd b) {return (Cd){a.x-b.x,a.y-b.y};}
    Cd operator * (Cd a,Cd b) {return (Cd){a.x*b.x-a.y*b.y,a.y*b.x+a.x*b.y};}
    Cd A[MAXN<<2],B[MAXN<<2];
    void fft(Cd *a,int n,int f)
    {
        rep(i,0,n-1) if(i<rev[i]) swap(a[i],a[rev[i]]);
        for(int i=1;i<n;i<<=1)
        {
            Cd wn(cos(pi/i),f*sin(pi/i));
            for(int j=0;j<n;j+=i<<1)
            {
                Cd w(1,0),x,y;
                for(int k=0;k<i;k++,w=w*wn)
                    x=a[k+j],y=a[k+j+i]*w,a[j+k]=x+y,a[j+k+i]=x-y;
            }
        }
        if(f==1) return ;rep(i,0,n-1) a[i].x/=(db)n;
    }
    int lg,lmt;
    void solve(Cd *a,Cd *b)
    {
        fft(a,lmt,1);fft(b,lmt,1);rep(i,0,lmt-1) a[i]=a[i]*b[i];
        fft(a,lmt,-1);
    }
    int main()
    {
    	rep(T,1,read())
    	{
    		n=read(),m=read(),sum=n+m;
    		scanf("%s%s",s1,s2);rep(j,0,m/2-1) swap(s2[j],s2[m-1-j]);
        	lg=ceil(log2(sum)),lmt=1<<lg;
        	rep(i,0,lmt-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1)),ans[i]=0;
        	rep(j,0,9)
        	{
        		rep(i,0,lmt-1) A[i]={0,0},B[i]={0,0};
        		rep(i,0,n-1) if(s1[i]!='0'+j&&s1[i]!='*') A[i]={1,0};
        		rep(i,0,m-1) if(s2[i]=='0'+j) B[i]={1,0};
        		solve(A,B);
        		rep(i,0,n+m-1) ans[i]+=(int)(A[i].x+0.5);
    		}
    		rep(i,0,m) cnt[i]=0;
    		rep(i,m-1,n-1) cnt[ans[i]]++;
    		rep(i,1,m) cnt[i]+=cnt[i-1];
    		rep(i,0,m) printf("%d
    ",cnt[i]);
    	}
    }
    

    (fft)会比(ntt)快不少

    D

    显然所有斜率相同的直线可以归为一组

    每次都应该与之前的尽可能不同

    所以每一轮从所有组里选一个出来加入集合,这样不断模拟直到所有边都被选过

    #include<bits/stdc++.h>
    #define inf 2139062143
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    #define MAXN 100100
    #define MOD 998244353
    #define Fill(a,x) memset(a,x,sizeof(a))
    #define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
    #define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
    #define ren for(int i=fst[x];i;i=nxt[i])
    #define pls(a,b) (a+b)%MOD
    #define mns(a,b) (a-b+MOD)%MOD
    #define mul(a,b) (1LL*(a)*(b))%MOD
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    using namespace std;
    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 x*f;
    }
    int gcd(int a,int b){return !b?a:gcd(b,a%b);}
    int n,tot,cnt[MAXN],ans;
    map<pii,int> m;
    vector<int> v[2];
    int main()
    {
        int a,b,c,d,g,now;rep(T,1,read())
        {
            scanf("%d",&n);m.clear();v[0].clear(),v[1].clear();
            rep(i,1,n) cnt[i]=0;
            rep(i,1,n)
            {
                
                scanf("%d%d%d%d",&a,&c,&b,&d);
                a=b-a,b=d-c,c=abs(a),d=abs(b);
                if(!a) a=0,b=1;else if(!b) a=1,b=0;
                else
                {
                    g=gcd(c,d);a/=g,b/=g;
                    if(a<0) a=-a,b=-b;
                }
                if(!m[{a,b}]) tot++,cnt[1]++,m[{a,b}]++;
                else cnt[m[{a,b}]]--,cnt[++m[{a,b}]]++;
            }
            rep(i,1,n) rep(j,1,cnt[i]) v[1].pb(i);
            ans=0;rep(i,1,n)
            {
                ans--;now=i&1;for(auto x:v[now]) 
                {
                    ans++;if(x>1) v[now^1].pb(x-1);
                    printf("%d
    ",ans);
                }
                v[now].clear();
            }
        }
    }
    

    E

    好像还挺有意思的(dp)

    F

    网络流的奇妙增广 咕

    G

    每次出现(m_i=1)都需要重新计算,预处理一下这种情况下的前缀和

    查询的时候判断一下(l,r)之间是否有断点即可

    #include<bits/stdc++.h>
    #define inf 2139062143
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    #define MAXN 100100
    #define MOD 998244353
    #define Fill(a,x) memset(a,x,sizeof(a))
    #define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
    #define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
    #define ren for(int i=fst[x];i;i=nxt[i])
    #define pls(a,b) (a+b)%MOD
    #define mns(a,b) (a-b+MOD)%MOD
    #define mul(a,b) (1LL*(a)*(b))%MOD
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    using namespace std;
    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 x*f;
    }
    int n,q,sum[MAXN][3],bl[MAXN],a[MAXN];char s[10];
    int hsh(char c){return isdigit(c)?c-'0':10+c-'A';}
    int main()
    {
    	int a,b;rep(T,1,read())
    	{
    		n=read(),q=read();rep(i,1,n) bl[i]=0;
    		rep(i,1,n)
    		{
    			bl[i]=(2-read())?i:0;scanf("%s",s);
    			rep(j,0,2) sum[i][j]=hsh(s[j<<1])*16+hsh(s[j<<1|1]);
    		}
    		rep(i,1,n) 
    		{
    			int j=i+1;while(!bl[j])
    			{
    				rep(k,0,2) sum[j][k]+=sum[j-1][k];
    				bl[j++]=i;
    			}
    			i=j-1;
    		}
    		while(q--)
    		{
    			a=read(),b=read();
    			if(bl[a-1]!=bl[b])
    				rep(i,0,2) printf("%02X",min(sum[b][i],255));
    			else 
    				rep(i,0,2) printf("%02X",min(sum[b][i]-sum[a-1][i],255));
    			puts("");
    		}
    	}
    }
    

    H

    分块 咕

    I

    暴力枚举走到每个点的(sum a_i)对应的最大(sum b_i)

    每次转移的时候使用归并排序,并且用单调栈优化掉(a<a',b<b‘)的这些显然没有用的点

    因为数据随机跑的还挺快的

    #include<bits/stdc++.h>
    #define inf 2139062143
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    #define MAXN 150 
    #define MOD 998244353
    #define Fill(a,x) memset(a,x,sizeof(a))
    #define rep(i,s,t) for(register int i=(s),i##end=(t);i<=i##end;++i)
    #define dwn(i,s,t) for(register int i=(s),i##end=(t);i>=i##end;--i)
    #define ren for(int i=fst[x];i;i=nxt[i])
    #define pls(a,b) (a+b)%MOD
    #define mns(a,b) (a-b+MOD)%MOD
    #define mul(a,b) (1LL*(a)*(b))%MOD
    #define pii pair<int,int>
    #define pb push_back
    using namespace std;
    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 x*f;
    }
    vector<pii>f[MAXN][MAXN];
    vector<pii>::iterator it1,it2;
    pii st[500005],tmp;ll ans;
    int n,A[MAXN][MAXN],B[MAXN][MAXN],sa[MAXN],sb[MAXN],tp;
    int main()
    {
    	rep(T,1,read())
        {
            scanf("%d",&n);ans=0;
            rep(i,1,n) rep(j,1,n) scanf("%d",&A[i][j]);
            rep(i,1,n) rep(j,1,n) scanf("%d",&B[i][j]);
            sa[0]=0;rep(j,1,n) sa[j]=sa[j-1]+A[1][j];
            sb[0]=0;rep(j,1,n) sb[j]=sb[j-1]+B[1][j];
            rep(j,1,n) f[1][j].pb({sa[j],sb[j]});
            rep(i,2,n)
            {
    			#define a first
    			#define b second
                it1=f[i-1][1].begin();tp=0;
                while(it1!=f[i-1][1].end())
                {
                    tmp={(it1->a)+A[i][1],(it1->b)+B[i][1]};
                    while(tp&&st[tp].a<=tmp.a&&st[tp].b<=tmp.b) tp--;
                    st[++tp]=tmp;
                    it1++;
    			}
                rep(k,1,tp) f[i][1].pb(st[k]);
                rep(j,2,n)
                {
                    it1=f[i-1][j].begin(),it2=f[i][j-1].begin();tp=0;
                    while(it1!=f[i-1][j].end()&&it2!=f[i][j-1].end())
                    {
                        if((it1->a)==(it2->a))
    						tmp={(it1->a)+A[i][j],max(it1->b,it2->b)+B[i][j]},it1++,it2++;
                        else if((it1->a)<(it2->a))
                        	tmp={(it1->a)+A[i][j],(it1->b)+B[i][j]},it1++;
                        else
    						tmp={(it2->a)+A[i][j],(it2->b)+B[i][j]},it2++;
                        while(tp&&st[tp].a<=tmp.a&&st[tp].b<=tmp.b) tp--;
                        st[++tp]=tmp;
                    }
                    while(it1!=f[i-1][j].end())
                    {
                        tmp={(it1->a)+A[i][j],(it1->b)+B[i][j]};
                        while(tp&&st[tp].a<=tmp.a&&st[tp].b<=tmp.b) tp--;
                        st[++tp]=tmp;
                        it1++;
                    }
                    while(it2!=f[i][j-1].end())
                    {
                        tmp={(it2->a)+A[i][j],(it2->b)+B[i][j]};
                        while(tp&&st[tp].a<=tmp.a&&st[tp].b<=tmp.b) tp--;
                        st[++tp]=tmp;
                        it2++;
                    }
                    rep(k,1,tp) f[i][j].pb(st[k]);
                }
                rep(j,1,n) f[i-1][j].clear();
            }
            for(it1=f[n][n].begin();it1!=f[n][n].end();it1++) ans=max(ans,1LL*(it1->a)*(it1->b));
            rep(j,1,n) f[n][j].clear();
            printf("%lld
    ",ans);
        }
    }
    

    J

    若只询问一次是一个经典的问题

    二分一个权值(xin[-w_m-1,w_m+1]),对所有白边权(+=x),求一个(MST),判断树里白边数量是否(ge need)

    最终得到一个白边边权加了(x),白边数量(ge need)的最小生成树,答案即为(MST)边权和(-needcdot x)

    (当白边(> need)时,对有解的情况来说,一定有一些(val_w+x==val_b)(MST)边权和不变,可以直接作差得到答案

    此题需要询问所有(need)

    有一个结论:最终的(MST)上所有边一定为纯黑的(MST)或纯白的(MST)上的边

    这样可以预处理出两个纯色(MST)上的边,将复杂度从(O(m))变为(O(n))

    由于值域较小,可以枚举所有加权(x),每次做一次最小生成树,对这种情况下的白边边数更新答案

    最后查询时对每个(x),由经典问题解法,根据最小(ge x)且有答案记录的(x),输出答案

    #include<bits/stdc++.h>
    #define inf 2139062143
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    #define MAXN 100100
    #define MOD 998244353
    #define Fill(a,x) memset(a,x,sizeof(a))
    #define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
    #define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
    #define ren for(int i=fst[x];i;i=nxt[i])
    #define pls(a,b) (a+b)%MOD
    #define mns(a,b) (a-b+MOD)%MOD
    #define mul(a,b) (1LL*(a)*(b))%MOD
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    using namespace std;
    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 x*f;
    }
    int n,m,k,fa[MAXN],tot,ans[MAXN],val[MAXN];
    struct Edge{int u,v,w;}e1[MAXN<<1],e2[MAXN<<1];
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    bool operator < (Edge &x,Edge &y){return x.w<y.w;}
    int merge(int u,int v)
    {
    	int fu=find(u),fv=find(v);
    	if(fu!=fv) return fa[fu]=fv;
    	else return 0;
    }
    void work(Edge *e)
    {
    	sort(e+1,e+m+1);tot=0;rep(i,1,n) fa[i]=i;
    	rep(i,1,m) if(merge(e[i].u,e[i].v)) e[++tot]=e[i];
    }
    void solve(int x)
    {
    	rep(i,1,n) fa[i]=i;int i=1,j=1,sum=0,num=0;
    	while(i<n&&j<n)
    	{
    		if(e2[j].w+x<=e1[i].w)
    			{if(merge(e2[j].u,e2[j].v)) sum+=e2[j].w+x,num++;j++;}
    		else 
    			{if(merge(e1[i].u,e1[i].v)) sum+=e1[i].w;i++;}
    	}
    	while(i<n)
    		{if(merge(e1[i].u,e1[i].v)) sum+=e1[i].w;i++;}
    	while(j<n)
    		{if(merge(e2[j].u,e2[j].v)) sum+=e2[j].w+x,num++;j++;}
    	ans[num]=sum,val[num]=x;
    }
    int main()
    {
    	rep(T,1,read())
    	{
    		n=read(),m=read();
    		rep(i,1,m)
    		{
    			scanf("%d%d%d%d",&e1[i].u,&e1[i].v,&e1[i].w,&e2[i].w);
    			e2[i].u=e1[i].u,e2[i].v=e1[i].v;
    		}
    		work(e1);work(e2);
    		rep(i,0,n-1) ans[i]=val[i]=0;
    		rep(i,0,1000) solve(i);
    		dwn(i,n-2,0) if(!ans[i]) ans[i]=ans[i+1],val[i]=val[i+1];
    		rep(i,0,n-1) printf("%d
    ",ans[i]-i*val[i]);
    	}
    }
    

    K

    签到题,因为线段树每层节点的长度只可能是相邻的数,暴力模拟即可

    #include<bits/stdc++.h>
    #define inf 2139062143
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    #define MAXN 100100
    #define MOD 998244353
    #define Fill(a,x) memset(a,x,sizeof(a))
    #define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
    #define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
    #define ren for(int i=fst[x];i;i=nxt[i])
    #define pls(a,b) (a+b)%MOD
    #define mns(a,b) (a-(b)+MOD)%MOD
    #define mul(a,b) (1LL*(a)*(b))%MOD
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    using namespace std;
    inline ll read()
    {
        ll 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 x*f;
    }
    ll ans,n,k,a[3],b[3],c[3],d[3];
    int main()
    {
    	rep(T,1,read())
    	{
    		n=read(),k=read();
    		a[1]=n,c[1]=1;a[2]=c[2]=0;ans=0;
    		while(a[1]||a[2])
    		{
    			ans+=c[1]+c[2];b[1]=0,b[2]=0,d[1]=d[2]=0;
    			if(a[1]>k)
    			{
    				if(a[1]&1) b[1]=a[1]/2,b[2]=a[1]/2+1,d[1]=c[1],d[2]=c[1];
    				else b[1]=a[1]/2,d[1]=c[1]<<1;
    			}
    			if(a[2]&&a[2]>k) 
    			{
    				if(a[2]&1) b[1]=a[2]/2,b[2]=a[2]/2+1,d[1]+=c[2],d[2]+=c[2];
    				else b[2]=a[2]/2,d[2]+=c[2]<<1;
    			}
    			a[1]=b[1],a[2]=b[2],c[1]=d[1],c[2]=d[2];
    		}
    		printf("%lld
    ",ans);
    	}
    }
    

    L

    极其麻烦的状压/轮廓线 咕

  • 相关阅读:
    sessionstorage中存储JSON数据
    JS + Canvas画图Demo
    JavaWeb中实现通过邮箱找回密码
    javaWeb实现验证码--代码超简单
    maven的下载、安装及配置
    web端百度地图API实现实时轨迹动态展现
    java存储数据到本地txt文件中
    java读取地址数据文件
    在服务器的tomcat中部署手机apk项目,浏览器或手机下载不能根据URL下载和安装apk文件
    虚拟机类加载机制
  • 原文地址:https://www.cnblogs.com/yyc-jack-0920/p/15081112.html
Copyright © 2020-2023  润新知