• 中山纪念中学培训杂题(难的都不在这里面qwq)


    来中山纪中半个月了,差不多就要结束了,
    写一些之前考试能更正的题解吧,还有一些不是给人做的(比如IOI2018互测。。
    备注:我不会的就没有放上来了,所有数学有关的基本上都死了。
    所以这里的题目都是相对其他考的而言简单的题qwq,然而我考场上还是不会做
    写完之后发现只会分块和线段树qwq,偶尔有点网络流,其他都不会,awsl

    3.18

    第一天来就考NOI NO.2的题目。。

    题目看这里吧

    more?more!

    这道题非常奇妙的地方在于
    因为(n)是固定的所以(n+1)本就是不需要求的状态,
    然后对于(O(n^2))就是(f_{n+1,i}=f_{n,i}*p^i+f_{n,i-1}*(1-p)^{n-i+1})
    利用(f_{n+1,i})是可以从两个方程中转移过来的,我们就可以得出有效状态(f_{n,i})了。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #define ll long long
    using namespace std;
    const ll N=1e6+6;
    const ll mod=998244353;
    ll n,p,inv[N],finv[N],f[N];
    ll read(){
    	ll x=0,w=1;char ch=getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    	return x*w;
    }
    
    void init(){
    	inv[1]=1;finv[1]=1;f[1]=1;
    	for(ll i=2;i<=n;i++)inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    	for(ll i=2;i<=n;i++)finv[i]=finv[i-1]*inv[i]%mod;
    	for(ll i=2;i<=n;i++)f[i]=f[i-1]*i%mod;
    }
    
    ll ksm(ll x,ll k){
    	ll ans=1;
    	while(k){
    		if(k&1)ans=(ans*x)%mod;x=(x*x)%mod;k>>=1;
    	}return ans%mod;
    }
    
    int main(){
    	freopen("more.in","r",stdin);
    	freopen("more.out","w",stdout);
    	n=read();p=read();init();
    	if(p==499122177){
    		for(ll i=1;i<n;i++){
    			ll sum=((finv[n-i]*finv[i])%mod)*f[n]%mod;
    			sum=(sum%mod*ksm(ksm(p,n-i)%mod,i))%mod;
    			printf("%lld ",sum);
    		}
    	}
    	else {
    		ll sum=1,tmp;
    		for(ll i=1;i<n;i++){
    			tmp=ksm(((ksm(p,i)-ksm((1-p+mod)%mod,i)+mod)%mod),mod-2)%mod;
    			sum=sum*(tmp*((ksm(p,n-i+1)-ksm((1-p+mod)%mod,n-i+1)+mod)%mod)%mod)%mod;
    			printf("%lld ",sum);
    		}
    	}
    	return 0;
    }
    

    3.19

    唯一比较容易的一天qwq

    题目看这里吧

    这里是官方题解

    T1

    数据结构维护dp
    第一题就是要下放很多的线段求满足条件的下方,二位偏序,然后卡线段树。
    二位偏序排个序就好了(我不会说我这个没想到qwq)
    线段树维护dp最大值->树状数组维护
    什么?你说树状数组(log^2),因为这里我们的序列是单调的,所以直接下放直接查就可以了,这种树状数组只能在这种情况下用。
    别人线段树比我树状数组快系列qwq
    哦对了,因为这道题叫fc,然后在Windows下面对拍也是fc,就变成了跑了两次这个代码,并没有比较文件输出。所以它全程没给我跑出错误,搞得我当时以为A了。

    #include<bits/stdc++.h>
    #define ll long long
    #define ls root<<1
    #define rs root<<1|1
    #define max(a,b) a>b?a:b
    using namespace std;
    const ll N=1e6+5;
    ll vis[21],n,m,ti[N],ai[N],ans,s[21];
    ll f[N],id[N];
    ll read(){
    	ll x=0,w=1;char ch=getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    	return x*w;
    }
    
    void work_20(){
    	for(ll i=0;i<(1<<n);i++){
    		ll sum=0,flag=0;memset(vis,0,sizeof(vis));
    		for(ll j=1;j<=n;j++)if((1<<(j-1))&i)vis[j]=1;
    		for(ll j=1;j<=n;j++)s[j]=s[j-1]+vis[j];
    		for(ll j=1;j<=n;j++)
    		if(vis[j]&&((s[min(j+ti[j],n)]-s[j-1]>1)||(s[j]-s[max(0ll,j-ti[j]-1)]>1)))flag=1;
    		if(flag)continue;
    		for(ll j=1;j<=n;j++)if(vis[j])sum+=ai[j];
    		ans=max(sum,ans);
    	}
    	cout<<ans<<endl;
    }
    
    void work_15(){
    	ll ans=0;
    	for(ll i=1;i<=n;i++)f[i]=ai[i];
    	for(ll i=1;i<=n;i++)
    		for(ll j=0;j<i;j++){
    		if(i-ti[i]<=j||ti[j]+j>=i)continue;
    		f[i]=max(f[i],f[j]+ai[i]);
    	}
    	for(int i=1;i<=n;i++)ans=max(ans,f[i]);
    	cout<<ans<<endl;
    }
    
    ll mx[N<<2],mx2[N<<2],lazy[N<<2];
    
    void update(int root,int left,int right,int v){
    	if(left==right){mx[root]=f[left];return ;}
    	int mid=(left+right)>>1;
    	if(mid>=v) update(ls,left,mid,v);
    	if(mid<v)  update(rs,mid+1,right,v);
    	mx[root]=max(mx[ls],mx[rs]);
    }
    
    ll query(int root,int left,int right,int l,int r){
    	if(left>r||right<l)return -99999999;
    	if(left>=l&&right<=r)return mx[root];
    	ll a=-99999999,b=-99999999,mid=(left+right)>>1;
    	if(mid>=l) a=query(ls,left,mid,l,r);
    	if(mid<r)  b=query(rs,mid+1,right,l,r);
    	return max(a,b);
    }
    
    bool cmp(int a,int b){
    	return a+ti[a]<b+ti[b];
    }
    
    ll c[N];
    
    void add(ll x){
    	for(ll i=x;i<=n;i+=(i&(-i)))c[i]=max(c[i],f[x]);
    }
    
    ll ask(ll x){
    	ll ans=0;for(ll i=x;i>=1;i-=(i&(-i)))ans=max(c[i],ans);return ans;
    }
    
    int main(){
    	freopen("fc.in","r",stdin);
    	freopen("fc.out","w",stdout);
    	n=read();ll flag=1;
    	for(int i=1;i<=n;i++){ti[i]=read();if(ti[i]!=ti[1])flag=0;}
    	for(int i=1;i<=n;i++)ai[i]=read()*ti[i];
    	for(int i=1;i<=n;i++)ti[i]--,id[i]=i;
    	if(n<=20){work_20();return 0;}
    	if(n<=5000){work_15();return 0;}
    	for(ll i=1;i<=n;i++)f[i]=ai[i];
    	if(flag){
    		for(ll i=1;i<=n;i++){
    			if(i-ti[i]-1>=1)
    			f[i]=query(1,1,n,1,i-ti[i]-1)+ai[i];
    			update(1,1,n,i);	
    		}
    	}else {
    		sort(id+1,id+n+1,cmp);int now=1;
    		for(int i=1;i<=n;i++){
    			while(id[now]+ti[id[now]]<i&&now<=n)add(id[now]),now++;
    			if(i-ti[i]-1>=1)f[i]=ask(i-ti[i]-1)+ai[i];
    		}
    	}
    	for(int i=1;i<=n;i++)ans=max(ans,f[i]);
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    T2

    就是因为这个东西,本来我已经放弃学SAM了的qwq。
    是关于SAM的模板题吧qwq
    就是考关于SAM的拼接。因为每个序列只能贡献连续的一段,所以我们从n到1把每个字符串的SAM连接起来。就是建的时候记录一下左右端点。然后拼起来,具体看代码吧。

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    const int N=4e6+5;
    const int mod=1e9+7;
    int f[N],n,a[N],tot,last,tmp[5],rt,ls[N],rs[N];
    char s[N],ss[N],b[N];
    struct node{
        int ch[7],len,ff;
    }t[N];
    int dfs(int x){
        if(f[x]!=-1)return f[x];
        f[x]=1;
        for(int i=1;i<=4;i++){
            f[x]+=dfs(t[x].ch[i]);
            f[x]%=mod;
        }return f[x];
    }
    
    void print(int x,int k){
        puts(ss);
        for(int i=1;i<=4;i++){
            if(t[x].ch[i]){
                ss[k]=b[i];
                print(t[x].ch[i],k+1);
            }
        }ss[k]=0;
    }
    
    void update(int x){
        int p=last,np=last=++tot;
        t[np].len=t[p].len+1;
        while(p&&!t[p].ch[x])t[p].ch[x]=np,p=t[p].ff;
        if(!p)t[np].ff=rt;
        else {
            int q=t[p].ch[x];
            if(t[q].len==t[p].len+1)t[np].ff=q;
            else{
                int nq=++tot;t[nq]=t[q];
                t[nq].len=t[p].len+1;t[q].ff=t[np].ff=nq;
                while(p&&t[p].ch[x]==q){t[p].ch[x]=nq;p=t[p].ff;}
            }
        }
    }
    
    int main(){
    	freopen("copy.in","r",stdin);
    	freopen("copy.out","w",stdout);
        memset(f,-1,sizeof(f));f[0]=0;
        a['A']=1;a['C']=2;a['G']=3;a['T']=4;
        b[1]='A';b[2]='C';b[3]='G';b[4]='T';
        cin>>n;
        for(int i=1;i<=n;i++){
            ls[i]=last=rt=++tot;
            scanf("%s",s+1);int len=strlen(s+1);
            for(int i=1;i<=len;i++)update(a[s[i]]);
            rs[i]=tot;
        }
        for(int i=n;i>=1;i--){
            for(int j=rs[i];j>=ls[i];j--){
                for(int k=1;k<=4;k++){
                    if(!t[j].ch[k])t[j].ch[k]=tmp[k];
                }
            }
            for(int k=1;k<=4;k++)
            tmp[k]=t[ls[i]].ch[k];
        }
        int k;cin>>k;
        if(k)print(1,0);
        printf("%d
    ",dfs(1));
        return 0;
    }
    

    T3

    卡常有点恶心啊qwq
    首先对于子序列我们需要用序列自动机(这并不是一个很高大上的东西)维护,不然你会跑很多的重复子序列
    肉眼可见的二分图匹配。但是如果我们把每个字符串的子序列都提出来连边建图不就炸了吗
    所以套路就在于我们对于每个字符串只要搞出300个关于它的子序列就可以了。
    因为这样就一定可以全部匹配了。
    好了目前时间复杂度(O(n^4)),二分啊。
    反正我的程序被卡了一点点时限,也可能有点错误吧,所以我有一个点是打表的。
    然后网络流是一定跑不过的别想了,然后我必须搞出1000个关于它的子序列才可以?
    如果有大佬可以看看我错哪里,蒟蒻感激不尽

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    vector<int>q[305][305];
    map<string,int>mp,mp2;
    const int N=301*301*50+5;
    const int inf=1e9;
    int n,tot,head[301],s,t,ans,cnt,nex[301][31],idx,a[301],ai[301];
    int num=1,dep[N],line[N],Q[100001],vis[100001];
    string ss[N],sss;
    struct node{
    	int to,nex,c;
    }e[N];
    
    void add(int from,int to){
    	e[++num].to=to;e[num].nex=head[from];head[from]=num;
    }
    
    int dfs(int x){
    	for(int i=head[x];i;i=e[i].nex){
    		int v=e[i].to;if(vis[v])continue;vis[v]=1;
    		if(!Q[v]||dfs(Q[v])){Q[v]=x;return 1;}
    	}return 0;
    }
    
    int get(){
    	int ans=0;
    	for(int i=1;i<=n;i++){for(int i=1;i<=tot;i++)vis[i]=0;ans+=dfs(i);}
    	return ans;
    }
    
    int find(){
    	int l=1,r=n;ans=-1;
    	while(r>=l){
    		int mid=(l+r+1)>>1;
    		num=0;memset(head,0,sizeof(head));for(int i=1;i<=tot;i++)Q[i]=0;
    		for(int i=1;i<=n;i++){
    			for(int j=1;j<=mid;j++)
    			for(int k=0;k<q[i][j].size();k++)
    			add(i,q[i][j][k]);//add(q[i][j][k],i);
    		}
    		if(get()==n){
    			r=mid-1;for(int i=n+1;i<=tot;i++)if(Q[i])line[Q[i]]=i;ans=mid;
    		}
    		else l=mid+1;
    	}
    }
    
    //void dfs(int id,int now,int x,int y,string S){
    //	if(cnt>310||now>sss.size())return ;
    ////	cerr<<id<<' '<<now<<' '<<x<<' '<<y<<' '<<S<<endl;
    //	if(x>=y){
    //		if(!mp[S])mp[S]=++tot,ss[tot]=S;
    //		if(!vis[mp[S]])cnt++,q[id][y].push_back(mp[S]),vis[mp[S]]=1;return ;
    //	}dfs(id,now+1,x+1,y,S+sss[now]);dfs(id,now+1,x,y,S);
    //}
    
    void init(){
    	int n=sss.size();
    	for(int i=n;i>=1;i--){
    		for(int j=1;j<=26;j++)
    		nex[i-1][j]=nex[i][j];	
    		if(i!=n)nex[i-1][sss[i]-'a'+1]=i;
    	}
    }
    
    void dfs(int id,int x,int y,int limit,string S){
    	if(cnt>1000||x>sss.size())return ;
    	if(y>=limit){
    		cnt++;
    		if(!mp[S])mp[S]=++tot,ss[tot]=S;q[id][limit].push_back(mp[S]);
    		return ;
    	}
    	for(int i=1;i<=26;i++)
    	if(nex[x][i])dfs(id,nex[x][i],y+1,limit,S+(char)(i+'a'-1));
    }
    
    int main(){
    	freopen("diff.in","r",stdin);
    	freopen("diff.out","w",stdout);
    	ios::sync_with_stdio(false);
    	cin>>n;tot=n;int flag=0;
    	for(int i=1;i<=n;i++){
    		cnt=0;
    		cin>>sss;int l=sss.size();
    		if(sss=="hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")flag=1;
    		if(!flag){
    			init();string S;S+=sss[0];
    			for(int j=1;j<=l;j++){
    				dfs(i,0,1,j,S);dfs(i,0,0,j,"");if(cnt>1000)break;
    			}
    		}
    		if(flag){
    			ai[i]=sss.size();
    			while(a[ai[i]])ai[i]--;a[ai[i]]=1;
    		}
    	}	
    	if(flag){
    		cout<<300<<endl;
    		for(int i=1;i<=n;i++){
    		for(int j=1;j<=ai[i];j++)
    		cout<<'h';
    		cout<<endl;
    		}return 0;
    	}
    	s=0,t=tot+1,find();
    	if(ans==-1){cout<<ans<<endl;return 0;}
    	else cout<<ans<<endl;
    	for(int i=1;i<=n;i++)cout<<ss[line[i]]<<endl;
    	return 0;
    }
    

    3.20

    今天自闭了,没交,盯着电脑看了四个小时。

    会改正的只有这一道

    网上有题解自己搜吧,据说还是错的。
    就是因为区间有包含情况所以不能这么转移。

    第二题就是加强版天天爱跑步,给你一颗树,m条路径,问你路径相交的个数,注路径有起点时间和终点时间,不相交于点上也是可以的,gaojiaxuan说还可以加强???

    第三题就是较强版八邻桥,八邻桥阵2333,就是变成了m条河道,你要怎么修。

    3.22

    又是自闭的一天。

    题目

    第一题构造。没得人写,写的都是随机。

    第二题多项式相关,wsl

    第三题,考场上算错复杂度了算出来的是(O(n*logn*sqrt n))
    其实是(O(n*logsqrt n*sqrt n))
    就是对于题目,我每次修改只会多出两个区间来,那么用set维护区间,对于每个区间直接((log^2))改,因为均摊下来最多((n+q))个区间所以是接近(O(n*log^2))的,主席树维护。
    好了说一大堆,其实我根本没用这个方法。还是分块好.jpg
    对于分块,直接维护每个块的乘积,然后修改的话打标记,修改时因为每个整块有b满了和没满的,所以维护b满了的一个数组,然后块内二分当前满了的然后快速幂没满的。

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const ll N=1e6+5;
    const ll mod=1e9+7;
    ll l[N],r[N],ans,a[N],b[N],c[N];
    ll mul[N],s[N],bl[N],f[N];
    ll n,q,tmp,mx[N];
    ll read(){
        ll x=0,w=1;char ch=getchar();
        while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*w;
    }
    
    ll ksm(ll x,ll k){
        ll ss=1;
        while(k){if(k&1)ss=(ss*x)%mod;x=(x*x)%mod;k>>=1;}
        return ss%mod;
    }
    
    void build(){
        tmp=sqrt(n);
        for(ll i=1;i<=tmp;i++)
        l[i]=(i-1)*tmp+1,r[i]=tmp*i;
        if(r[tmp]<n)tmp++;
        l[tmp]=r[tmp-1]+1,r[tmp]=n;
        for(ll i=1;i<=tmp;i++){
            for(ll j=l[i];j<=r[i];j++)
            mx[i]=max(mx[i],a[j]),bl[j]=i,c[j]=b[j];sort(c+l[i],c+r[i]+1);
            for(ll j=l[i];j<=r[i];j++)
            {mul[j]=c[j];if(j>l[i])mul[j]=(mul[j]*mul[j-1])%mod;}
            ll sum=1;
            for(ll j=l[i];j<=r[i];j++)
            sum=(sum*min(b[j],a[j]))%mod;s[i]=sum;
        }
    }
    
    void change(ll x,ll y){
        b[x]=y;s[bl[x]]=1;
        for(ll i=l[bl[x]];i<=r[bl[x]];i++)c[i]=b[i];
        sort(c+l[bl[x]],c+r[bl[x]]+1);
        for(ll i=l[bl[x]];i<=r[bl[x]];i++)
        {mul[i]=c[i];if(i>l[bl[x]])mul[i]=(mul[i]*mul[i-1])%mod;}
        if(f[bl[x]]){for(ll i=l[bl[x]];i<=r[bl[x]];i++)s[bl[x]]=(s[bl[x]]*min(f[bl[x]],b[i]))%mod;}
        else for(ll i=l[bl[x]];i<=r[bl[x]];i++)s[bl[x]]=(s[bl[x]]*min(a[i],b[i]))%mod;
    }
    
    ll add(ll x,ll y){
        f[x]=mx[x]=y;s[x]=1;
        ll u=lower_bound(c+l[x],c+r[x]+1,y)-c-1;
        if(u+1<=r[x])s[x]=(ksm(y,r[x]-u))%mod;
        if(u>r[x])u=r[x];
        if(u>=l[x])s[x]=(s[x]*mul[u])%mod;
    }
    
    int main(){
        freopen("magic.in","r",stdin);
        freopen("magic.out","w",stdout);
        n=read();q=read();
        for(ll i=1;i<=n;i++)a[i]=read();
        for(ll i=1;i<=n;i++)a[i]=max(a[i],a[i-1]);
        for(ll i=1;i<=n;i++)b[i]=read();
        build();
        for(ll i=1;i<=q;i++){
            ll opt=read();ans=1;
            if(opt==0){
                ll x=read(),y=read(),ss=0;
                if(f[bl[x]])for(ll i=l[bl[x]];i<=r[bl[x]];i++)a[i]=max(a[i],f[bl[x]]);f[bl[x]]=0;
                for(ll i=x;i<=r[bl[x]];i++)a[i]=max(a[i],y),mx[bl[x]]=max(a[i],mx[bl[x]]);
                s[bl[x]]=1;for(ll i=l[bl[x]];i<=r[bl[x]];i++)s[bl[x]]=(s[bl[x]]*min(a[i],b[i]))%mod;
                ll j=bl[x]+1;
                while(mx[j]<y&&j<=tmp)add(j,y),j++;
                if(j<=tmp){
                    for(ll k=l[j];k<=r[j];k++)a[k]=max(a[k],max(f[j],y));
                    s[j]=1;for(ll k=l[j];k<=r[j];k++)s[j]=(s[j]*min(a[k],b[k]))%mod;
                }
                for(ll j=1;j<=tmp;j++)ans=(ans*s[j])%mod;
                printf("%lld
    ",ans%mod);
            }else {
                ll x=read(),y=read();change(x,y);
                for(ll j=1;j<=tmp;j++)ans=(ans*s[j])%mod;
                printf("%lld
    ",ans%mod);
            }
        }
        return 0;
    }
    

    3.23

    考了CJ他们的题目
    本来就是因为CJ不收去的JZ。然后我在JZ考CJ。ZYYS

    第一题。。。分类讨论后没打了,自我感觉和毒瘤很像
    第二题。。。神仙组合不过被gaojiaxuan用了一个套路然后好像是可以多项式做出来,据会多项式的人说特别简单比题解良心多了。

    只会网络流

    考虑最小割。
    S连体力流量为1,T连智力流量为1,然后把天数拆点,拆点之间连边流量为1。
    然后按题目要求把天数和任务连inf边。
    就是说要么这天必须选,要么就是这天要做的任务之前已经被做完了。
    一个让人误认为是跑最大答案的网络流。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    using namespace std;
    const int N=1e5+5;
    const int inf=1e9;
    int num=1,head[N],k;
    int vis[N],dep[N],ti[N],n,m,s,t;
    struct node{
        int to,nex,c;
    }e[N<<1];
    int read(){
        int x=0,w=1;char ch=getchar();
        while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*w;
    }
    
    void add(int from,int to,int c){
        e[++num].to=to;e[num].c=c;e[num].nex=head[from];head[from]=num;
    }
    
    bool bfs(){
        memset(dep,0,sizeof(dep));dep[s]=1;
        queue<int>q;q.push(s);
        while(!q.empty()){
            int u=q.front();q.pop();
            for(int i=head[u];i;i=e[i].nex){
                int v=e[i].to;
                if(!dep[v]&&e[i].c)q.push(v),dep[v]=dep[u]+1;
            }
        }return dep[t];
    }
    
    int dfs(int x,int cap){
        if(x==t)return cap;
        int addx=0;
        for(int i=head[x];i;i=e[i].nex){
            int v=e[i].to;
            if(dep[v]==dep[x]+1&&e[i].c){
                int tmp=dfs(v,min(e[i].c,cap-addx));
                e[i].c-=tmp;e[i^1].c+=tmp;addx+=tmp;
            }
        }return addx;
    }
    
    int dinic(){
        int ans=0;while(bfs())ans+=dfs(s,inf);return ans;
    }
    
    int main(){
        freopen("deadline.in","r",stdin);
        freopen("deadline.out","w",stdout);
        n=read();m=read();k=read();s=0;t=m+m+n+1;
        for(int i=1;i<=m;i++)add(i,i+m,1),add(i+m,i,0);
        for(int i=1;i<=n;i++){
            ti[i]=read();
            if(ti[i])add(i+m+m,t,1),add(t,i+m+m,0);
            else add(s,i+m+m,1),add(i+m+m,s,0);
        }
        for(int i=1;i<=k;i++){
            int x=read(),y=read();
            if(!ti[x]) add(x+m+m,y,inf),add(y,x+m+m,0);
            else  add(y+m,x+m+m,inf),add(x+m+m,y+m,0);
        }
        printf("%d
    ",dinic());
        return 0;
    }
    

    3.25

    没有更正题目。想知道题目问问租酥雨大佬他出的省选联考吧。
    反正数学那么多我是自闭了。

    3.26

    题目
    样例

    好像是最大子权闭合图的模板题吧。
    对于维护两颗不同的树共同连通块,我们考虑对于每一个根跑一次网络流,把它按照题目描述建边,也就是把两颗树的边放到一棵树里面,注意在网络流里的意思是,学了它,它往上的父亲也都被学了,这样就可以维护连通块了。
    又不知道为什么,我建图的树边不能重复。也就是两点之间只能有一条inf边。但是fish和jeff的可以???

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    using namespace std;
    const int N=2e3+5;
    const int inf=1e7;
    int n,s,t,num,head[N],dep[N],ch[101][101];
    int ans=0,sum=0,a[N],cnt=0;
    struct edge{
        int to,nex,c;
    }e[N*100];
    int read(){
    	int x=0,w=1;char ch=getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    	return x*w;
    }
    void add(int from,int to,int c){
        num++;e[num].to=to;e[num].c=c;e[num].nex=head[from];head[from]=num;
    }
    struct node{
        int num=0,head[N];
        edge e[N*100];
        void clean(){memset(head,0,sizeof(head));num=0;}
        void add(int from,int to){
            num++;e[num].to=to;e[num].nex=head[from];head[from]=num;
        } 
    }A,B;
    void dfs1(int x,int ff){
        for(int i=A.head[x];i;i=A.e[i].nex){
            int v=A.e[i].to;if(v==ff)continue;
        	if(!ch[v][x])add(v,x,inf),add(x,v,0),ch[v][x]=1;dfs1(v,x);
        }
    }
    void dfs2(int x,int ff){
        for(int i=B.head[x];i;i=B.e[i].nex){
            int v=B.e[i].to;if(v==ff)continue;
        	if(!ch[v][x])add(v,x,inf),add(x,v,0),ch[v][x]=1;dfs2(v,x);
        }
    }
    bool bfs(){ 
        memset(dep,0,sizeof(dep));dep[s]=1;int tot=0;
        queue<int>q;q.push(s);
        while(!q.empty()){
            int u=q.front();q.pop();
            for(int i=head[u];i;i=e[i].nex){
                int v=e[i].to;
                if(!dep[v]&&e[i].c)dep[v]=dep[u]+1,q.push(v);
            }
        }return dep[t];
    }
    
    int dfs(int x,int cap){
        if(x==t)return cap;
        int addx=0;
        for(int i=head[x];i;i=e[i].nex){
            int v=e[i].to;cnt++;
            if(dep[v]==dep[x]+1&&e[i].c){
                int tmp=dfs(v,min(cap-addx,e[i].c));
                e[i].c-=tmp;e[i^1].c+=tmp;addx+=tmp;
            }
        }return addx;
    }
    
    int dinic(){
        int ans=0;while(bfs())cnt=0,ans+=dfs(s,inf);return ans;
    }
    
    void solve(){
        n=read();ans=inf;sum=0;s=0;t=n+1;
        A.clean();B.clean();
        int ff=1;
        for(int i=1;i<=n;i++)a[i]=read(),sum+=a[i]>0?a[i]:0;
        for(int i=1;i<n;i++){
            int x=read(),y=read();
            A.add(x,y);A.add(y,x);
        }
        for(int i=1;i<n;i++){
            int x=read(),y=read();
            B.add(x,y);B.add(y,x);
        }
        for(int i=1;i<=n;i++){
        	memset(ch,0,sizeof(ch));
            memset(head,0,sizeof(head));num=1;
            for(int j=1;j<=n;j++){
                if(a[j]>0)add(s,j,a[j]),add(j,s,0);
                else add(j,t,-a[j]),add(t,j,0);
            }
            dfs1(i,i);dfs2(i,i);
            int tmp=dinic();
            ans=min(ans,tmp);
        }printf("%d
    ",sum-ans);
    }
    
    int main(){
    	freopen("name.in","r",stdin);
    	freopen("name.out","w",stdout);
        int T=read();
        while(T--)solve();
        return 0;
    }
    

    3.27

    事先说明这道题不卡(log^3)
    题目
    题解

    题解应该已经很清楚了吧qwq

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<cmath>
    #include<queue>
    #define ls root<<1
    #define rs root<<1|1
    using namespace std;
    const int N=5e5+5;
    const int inf=1e9;
    int lazy[N<<2],s[N<<2];
    int n,m,num,head[N],wi[N],dep[N];
    int size[N],fa[N],st[N][21],ed[N][21];
    int visd[N],visb[N],idd[N],idb[N],bfsid,dfsid;
    struct edge{
        int to,nex;
    }e[N<<1];
    int read(){
        int x=0,w=1;char ch=getchar();
        while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*w;
    }
    
    void add(int from,int to){
        num++;e[++num].to=to;e[num].nex=head[from];head[from]=num;
    }
    
    struct node{
        int c[N];
        void add(int x){for(int i=x;i<=n;i+=(i&(-i)))c[i]+=1;}
        int query(int x){int ans=0;for(int i=x;i;i-=(i&(-i)))ans+=c[i];return ans;}
    }T;
    
    void dfs(int x){
        idd[x]=++dfsid;visd[dfsid]=x;size[x]=1;
        for(int i=head[x];i;i=e[i].nex){
            int v=e[i].to;if(dep[v])continue;
            dep[v]=dep[x]+1;fa[v]=x;dfs(v);size[x]+=size[v];
        }
    }
    
    void bfs(){
        queue<int>q;q.push(1);
        while(!q.empty()){
            int x=q.front();q.pop();idb[x]=++bfsid;visb[bfsid]=x;
            for(int i=head[x];i;i=e[i].nex){
                int v=e[i].to;if(v==fa[x])continue;q.push(v);
            }
        }
    }
    
    void init(int x){
        int left=0,right=0;
        for(int i=head[x];i;i=e[i].nex){
            int v=e[i].to;if(v==fa[x])continue;init(v);
        }st[x][0]=idb[x];ed[x][0]=idb[x];
        for(int i=1;i<=20;i++){
            left=right=0;
            for(int j=head[x];j;j=e[j].nex){
                int v=e[j].to;if(v==fa[x]||!st[v][i-1])continue;
                if(!left)left=v;right=v;
            }
            st[x][i]=st[left][i-1];ed[x][i]=ed[right][i-1];
            if(st[x][i]>ed[x][i])swap(st[x][i],ed[x][i]);
        }
    }
    
    void build(int root,int l,int r){
        if(l==r){
            s[root]=wi[visb[l]];return ;
        }int mid=(l+r)>>1;
        build(ls,l,mid);build(rs,mid+1,r);
        s[root]=min(s[ls],s[rs]);
    }
    
    void push(int root,int left,int right){
        int mid=(left+right)>>1;
        lazy[ls]+=lazy[root];lazy[rs]+=lazy[root];
        s[ls]+=lazy[root];s[rs]+=lazy[root];
        lazy[root]=0;return ;
    }
    
    void update(int root,int left,int right,int l,int r,int v){
        if(left>=l&&right<=r){s[root]-=v;lazy[root]-=v;return ;}
        if(lazy[root])push(root,left,right);
        int mid=(left+right)>>1;
        if(mid>=l) update(ls,left,mid,l,r,v);
        if(mid<r)  update(rs,mid+1,right,l,r,v);
        s[root]=min(s[ls],s[rs]);
    }
    
    void update2(int root,int left,int right,int k){
        if(left==right){s[root]=inf;return ;}
        if(lazy[root])push(root,left,right);
        int mid=(left+right)>>1;
        if(mid>=k) update2(ls,left,mid,k);
        if(mid<k)  update2(rs,mid+1,right,k);
        s[root]=min(s[ls],s[rs]);
    }
    
    int query(int root,int left,int right,int k){
        int mid=(left+right)>>1;
        if(left==right){return left;}
        if(lazy[root])push(root,left,right);
        if(s[ls]==k) return query(ls,left,mid,k);
        else return query(rs,mid+1,right,k);
    }
    
    int ask(int root,int left,int right,int k){
        int mid=(left+right)>>1;
        if(left==right){return s[root];}
        if(lazy[root])push(root,left,right);
        if(mid>=k) return ask(ls,left,mid,k);
        else return ask(rs,mid+1,right,k);
    }
    
    int main(){
        freopen("pang.in","r",stdin);
        freopen("pang.out","w",stdout);
        n=read();
        for(int i=1;i<=n;i++)wi[i]=read();
        for(int i=1;i<n;i++){
            int x=read(),y=read();
            add(x,y);add(y,x);
        }dep[1]=1;dfs(1);bfs();init(1);
        build(1,1,n);
        m=read();
        for(int i=1;i<=m;i++){
            int opt=read();
            if(opt==1){
                int x=read(),y=read(),d=0;
                for(int i=0;i<=15;i++){if(st[x][i])update(1,1,n,st[x][i],ed[x][i],(int)(y/pow(2,i)));}
                while(fa[x]&&(int)(y/pow(2,d))){
                    d++;
                    for(int i=1;i<=15;i++)
                    if(st[fa[x]][i]&&st[x][i-1]){update(1,1,n,st[x][i-1],ed[x][i-1],-(int)(y/pow(2,i+d)));}
                    x=fa[x];
    				for(int i=0;i<=15;i++)
                    if(st[x][i]){update(1,1,n,st[x][i],ed[x][i],(int)(y/pow(2,i+d)));}
                }
                    while(s[1]<=0){int tmp;T.add(idd[visb[tmp=query(1,1,n,s[1])]]);update2(1,1,n,tmp);}
            }else{
                int x=read();
                printf("%d
    ",T.query(idd[x]+size[x]-1)-T.query(idd[x]-1));
            }
        }
        return 0;
    }
    

    后记

    还有两天就要回来啦,省选退役预定了。

  • 相关阅读:
    www.verycd.com
    HDU-5281
    HDU-5280
    UVALive 6426
    hihocoder 1178 : 计数
    hihocoder 1177 : 顺子
    HDU-5272
    Tomcat 部署项目的三种方法
    Oracle数据库PLSQL的中文乱码显示全是问号
    ORACLE的sign函数和DECODE函数
  • 原文地址:https://www.cnblogs.com/hhh1109/p/10617271.html
Copyright © 2020-2023  润新知