• POI2012题解


    #2281. 「POI2012」字母 Letters

    对应过来做一遍逆序对就好了。

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 1e9
    const int maxn=1e6+10;
    const int mod=1e9+7;
    const int N=30;
    int n,a[maxn],now[N];
    long long ans;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    string s1,s2;
    int pre[N],fir[N],nxt[maxn];
    int c[maxn];
    int main(){
    	n=read();
    	cin>>s2>>s1;
    	for(int i=1;i<=n;i++){
    		int t=s1[i-1]-'A'+1;
    		if(!fir[t])fir[t]=pre[t]=i;
    		else nxt[pre[t]]=i,pre[t]=i;
    	}
    	for(int i=1;i<=n;i++){
    		int t=s2[i-1]-'A'+1;
    		if(!now[t])now[t]=fir[t];
    		a[i]=now[t];
    		now[t]=nxt[now[t]];
    	}
    	for(int i=n;i>=1;i--){
    		for(int j=a[i];j;j-=(j&(-j)))ans+=c[j];
    		for(int j=a[i];j<=n;j+=(j&(-j)))c[j]++;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    #2692. 「POI2012」井 Well

    没看到只能减不能加,没考虑(0)就半天想不会……

    二分答案(mid),前后扫求出不考虑(a_k=0)的答案(tot)

    考虑将一个点变为(0)会产生什么影响:过此点作斜率为(pm mid)的两条直线,直线以上的点都受影响。

    因为它的波动幅度不超过(mid),故影响范围是一个区间。

    维护区间左右端点即可。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int maxn=1e6+10;
    const int mod=1e9+7;
    int n,m,a[maxn];
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    int b[maxn],sum[maxn],cost[maxn];
    inline int check(int val){
    	int tot=0;
    	for(int i=1;i<=n;i++)b[i]=a[i];
    	for(int i=2;i<=n;i++)
    		if(b[i]>b[i-1]+val){
    			tot+=b[i]-b[i-1]-val;
    			b[i]=b[i-1]+val;
    		}
    	for(int i=n-1;i>=1;i--)
    		if(b[i]>b[i+1]+val){
    			tot+=b[i]-b[i+1]-val;
    			b[i]=b[i+1]+val;
    		}
    	for(int i=1;i<=n;i++)
    		sum[i]=sum[i-1]+b[i];
    	for(int i=n,l=n;i;i--){
    		while(l&&b[l]>(i-l)*val)l--;
    		cost[i]=sum[i]-sum[l]-val*(i-l)*(i-l-1)/2;
    	}
    	for(int i=1,r=1;i<=n;i++){
    		while(r<=n&&b[r]>(r-i)*val)r++;
    		if(tot+cost[i]+sum[r-1]-sum[i]-val*(r-i)*(r-i-1)/2<=m)
    			return i;
    	}
    	return 0;
    }
    signed main(){
    	n=read(),m=read();
    	for(int i=1;i<=n;i++)
    		a[i]=read();
    	int l=0,r=1<<30,ans=0;
    	while(l<=r){
    		int mid=(l+r)>>1;
    		if(check(mid))ans=mid,r=mid-1;
    		else l=mid+1;
    	}
    	printf("%lld %lld
    ",check(ans),ans);
    	return 0;
    }
    

    #2689. 「POI2012」节日 Festival

    不要以为数据范围大就不能用( ext{floyd}),只要你想不到别的方法,那它就可以。

    算是几乎把差分约束有学了一遍吧(也不知道以前我学了个啥)。

    连边如下:(add(a_i,b_i,1),add(b_i,a_i,-1),add(d_i,c_i,0))

    跑一边( ext{tarjan})缩点,考虑每个强连通分量。

    一个( ext{scc})内,显然由于大小关系卡得很死,那么它的取值就是最短路,它的贡献则是直径加一。

    出现负环即为不合法,由于我们对每个( ext{scc})( ext{floyd})过了,只需判断(dis[i][i]<0)即可。

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 1e9
    const int maxn=5e5+10;
    const int mod=1e9+7;
    const int N=666;
    int n,m1,m2,ans;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    int beg[N],nex[maxn],to[maxn],e;
    inline void add(int x,int y){
    	e++;nex[e]=beg[x];
    	beg[x]=e;to[e]=y;
    }
    int dis[N][N],col[N],scc;
    int dfn[N],low[N],ti,ins[N];
    stack<int>st;
    inline void tarjan(int x){
    	dfn[x]=low[x]=++ti;
    	st.push(x);ins[x]=1;
    	for(int i=beg[x];i;i=nex[i]){
    		int t=to[i];
    		if(!dfn[t]){
    			tarjan(t);
    			low[x]=min(low[x],low[t]);
    		}else if(ins[t])
    			low[x]=min(low[x],dfn[t]);
    	}
    	if(dfn[x]==low[x]){
    		col[x]=++scc;
    		ins[x]=0;
    		while(st.top()!=x){
    			int t=st.top();
    			st.pop();
    			col[t]=scc;
    			ins[t]=0;
    		}
    		st.pop();
    	}
    }
    int main(){
    	n=read(),m1=read(),m2=read();
    	memset(dis,0x3f,sizeof(dis));
    	for(int i=1;i<=n;i++)
    		dis[i][i]=0;
    	int x,y;
    	for(int i=1;i<=m1;i++){
    		x=read(),y=read();
    		add(x,y),add(y,x);
    		dis[x][y]=min(dis[x][y],1);
    		dis[y][x]=-1;
    	}
    	for(int i=1;i<=m2;i++){
    		x=read(),y=read();
    		add(y,x);
    		dis[y][x]=min(dis[y][x],0);
    	}
    	for(int i=1;i<=n;i++)
    		if(!dfn[i])tarjan(i);
    	for(int t=1;t<=scc;t++){
    		for(int i=1;i<=n;i++)
    			if(col[i]==t)
    			for(int j=1;j<=n;j++)
    				if(col[j]==t)
    				for(int k=1;k<=n;k++)
    					if(col[k]==t)
    						dis[j][k]=min(dis[j][k],dis[j][i]+dis[i][k]);
    		int len=-inf;
    		for(int i=1;i<=n;i++)
    			if(col[i]==t)
    			for(int j=1;j<=n;j++)
    				if(col[j]==t)len=max(len,dis[i][j]);
    		ans+=len+1;
    	}
    	for(int i=1;i<=n;i++)
    		if(dis[i][i]<0)return puts("NIE"),0;
    	printf("%d
    ",ans);
    	return 0;
    }
    
    

    #2690. 「POI2012」距离 Distance

    容易得出(d(a,b)=f(a)+f(b)-2f(gcd(a,b))),其中(f(i))(i)的质因数个数。

    套路:考虑枚举(gcd),更新答案,时间复杂度(Theta(nln n))

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 1e9
    const int maxn=1e6+10;
    const int mod=1e9+7;
    int n,a[maxn];
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    int pri[maxn],tot,flag[maxn];
    int f[maxn];
    int nxt[maxn],hd[maxn];
    int q[maxn];
    int ans[maxn],pos[maxn];
    int main(){
    	n=read();
    	for(int i=1;i<=n;i++)
    		a[i]=read();
    	for(int i=2;i<maxn;i++){
    		if(!flag[i])pri[++tot]=i,f[i]=1;
    		for(int j=1;j<=tot&&i*pri[j]<maxn;j++){
    			flag[i*pri[j]]=1;f[i*pri[j]]=f[i]+1;
    			if(i%pri[j]==0)break;
    		}
    	}
    	/*
    	for(int i=1;i<=tot;i++)
    		for(int j=pri[i];j<maxn;j+=pri[i])
    			f[j]++;
    	*/
    	for(int i=1;i<=n;i++)
    		nxt[i]=hd[a[i]],hd[a[i]]=i;
    	for(int i=1;i<=n;i++)
    		ans[i]=pos[i]=inf;
    	for(int i=1;i<maxn;i++){
    		int top=0;
    		for(int j=i;j<maxn;j+=i)
    			for(int k=hd[j];k;k=nxt[k])
    				q[++top]=k;
    		if(top<=1)continue;
    		int p=q[1];
    		for(int j=2;j<=top;j++)
    			if(f[a[p]]>f[a[q[j]]]||(f[a[p]]==f[a[q[j]]]&&p>q[j]))p=q[j];
    		for(int j=1;j<=top;j++){
    			if(q[j]==p)continue;
    			int val=f[a[q[j]]]+f[a[p]]-2*f[i];
    			if(val<ans[q[j]]||(val==ans[q[j]]&&pos[q[j]]>p))
    				ans[q[j]]=val,pos[q[j]]=p;
    			if(val<ans[p]||(val==ans[p]&&pos[p]>q[j]))
    				ans[p]=val,pos[p]=q[j];
    		}
    	}
    	for(int i=1;i<=n;i++)
    		printf("%d
    ",pos[i]);
    	return 0;
    }
    

    #2691. 「POI2012」约会 Rendezvous

    若两点在同一内向树上,则求(lca),否则先走到环上然后解决。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=5e5+10;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    int n,m,s1[maxn],t1[maxn],tot;
    int fa[maxn],rd[maxn];
    inline int find(int x){
    	if(fa[x]==x)return x;
    	return fa[x]=find(fa[x]);
    }
    int beg[maxn],nex[maxn],to[maxn],e;
    inline void add(int x,int y){
    	e++;nex[e]=beg[x];
    	beg[x]=e;to[e]=y;
    }
    int f[maxn][20],dep[maxn],rt[maxn];
    int col[maxn],sz[maxn],id[maxn];
    inline void dfs(int x,int anc,int root){
    	f[x][0]=anc;
    	for(int i=1;i<=19;i++)
    		f[x][i]=f[f[x][i-1]][i-1];
    	dep[x]=dep[anc]+1;
    	rt[x]=root;
    	for(int i=beg[x];i;i=nex[i])
    		if(to[i]!=anc&&col[to[i]]!=col[root])
    			dfs(to[i],x,root);
    }
    inline int lca(int x,int y){
    	if(dep[x]<dep[y])swap(x,y);
    	for(int i=19;i>=0;i--)
    		if(dep[f[x][i]]>=dep[y])x=f[x][i];
    	if(x==y)return x;
    	for(int i=19;i>=0;i--)
    		if(f[x][i]!=f[y][i]){
    			x=f[x][i];
    			y=f[y][i];
    		}
    	return f[x][0];
    }
    
    int main(){
    	n=read(),m=read();
    	for(int i=1;i<=n;i++)
    		fa[i]=i;
    	int x,y;
    	for(int i=1;i<=n;i++){
    		x=i,y=read();
    		if(find(x)!=find(y)){
    			add(y,x);
    			f[x][0]=y;
    			rd[x]++;
    			fa[find(x)]=find(y);
    		}else tot++,s1[tot]=y,t1[tot]=x;
    	}
    	for(int i=1;i<=tot;i++){
    		x=s1[i],y=t1[i];
    		int cnt=0;
    		while(x!=y){
    			col[x]=i;sz[i]++;
    			id[x]=++cnt;x=f[x][0];
    		}
    		col[y]=i;sz[i]++;
    		id[y]=sz[i];
    	}
    	dep[0]=-1;
    	for(int i=1;i<=n;i++)
    		if(col[i])dfs(i,0,i);
    	//for(int i=1;i<=n;i++)
    	//	printf("dep[%d]=%d rt[%d]=%d
    ",i,dep[i],i,rt[i]);
    	for(int i=1;i<=m;i++){
    		x=read(),y=read();
    		if(find(x)!=find(y)){
    			puts("-1 -1");
    			continue;
    		}
    		if(rt[x]==rt[y]){
    			int anc=lca(x,y);
    			printf("%d %d
    ",dep[x]-dep[anc],dep[y]-dep[anc]);
    			continue;
    		}
    		int a=dep[x],b=dep[y],c=col[rt[x]];
    		int s=(id[rt[y]]-id[rt[x]]+sz[c])%sz[c],t=sz[c]-s;
    		//printf("s=%d t=%d
    ",s,t);
    		int p=max(a+s,b),q=max(a,b+t);
    		int p1=min(a+s,b),q1=min(a,b+t);
    		if(p<q||(p==q&&p1<=q1))printf("%d %d
    ",a+s,b);
    		else printf("%d %d
    ",a,b+t);
    	}
    	return 0;
    }
    

    #2694. 「POI2012」糖果店 Vouchers

    不知道为什么感觉波兰人好喜欢链表啊。

    这题就维护每个值取到什么地方了,复杂度(Theta(n ln n)),要开( ext{long long})

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int maxn=1e6+10;
    const int N=1e6+1;
    const int mod=1e9+7;
    int n,m,a[maxn];
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    int hd[maxn],vis[maxn],cnt;
    int ans[maxn],tot;
    signed main(){
    	m=read();
    	int x,y;
    	for(int i=1;i<=m;i++)
    		x=read(),a[x]=1;
    	for(int i=1;i<N;i++)hd[i]=i;
    	n=read();
    	for(int i=1;i<=n;i++){
    		x=read(),y=0;
    		while(hd[x]<N&&y<x){
    			if(!vis[hd[x]]){
    				vis[hd[x]]=1;y++;
    				if(a[hd[x]])ans[++tot]=cnt+y;
    			}hd[x]+=x;
    		}cnt+=x;
    	}
    	sort(ans+1,ans+1+tot);
    	printf("%lld
    ",tot);
    	for(int i=1;i<=tot;i++)
    		printf("%lld
    ",ans[i]);
    	return 0;
    }
    
    

    #2695. 「POI2012」衣帽间 Cloakroom

    离线是个好东西。可惜我没想到。

    考虑离线,从小到大加入(a_i),维护(f_i),记录凑到(i)的方案的最小值的最大值。

    状态转移方程有(f_i=max{f_i,min{f_{i-c},b}})

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 1e9
    const int maxn=1e6+10;
    const int mod=1e9+7;
    int n,m,f[maxn],ans[maxn];
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    struct node{
    	int c,a,b;
    	bool operator<(const node &x){
    		return a<x.a;
    	}
    }p[maxn];
    struct query{
    	int m,k,s,id;
    	bool operator<(const query &x){
    		return m<x.m;
    	}
    }q[maxn];
    inline void insert(int x){
    	for(int i=100000;i>=p[x].c;i--)
    		if(~f[i-p[x].c])f[i]=max(f[i],min(f[i-p[x].c],p[x].b));
    }
    int main(){
    	n=read();
    	for(int i=1;i<=n;i++)
    		p[i]=(node){read(),read(),read()};
    	m=read();
    	for(int i=1;i<=m;i++)
    		q[i]=(query){read(),read(),read(),i};
    	sort(p+1,p+1+n);sort(q+1,q+1+m);
    	memset(f,-1,sizeof(f));f[0]=inf;
    	for(int i=1,j=1;i<=m;i++){
    		while(j<=n&&p[j].a<=q[i].m)insert(j++);
    		ans[q[i].id]=(f[q[i].k]>q[i].m+q[i].s);
    	}
    	for(int i=1;i<=m;i++)
    		puts(ans[i]?"TAK":"NIE");
    	return 0;
    }
    
    

    #2696. 「POI2012」可怕的诗 A Horrible Poem

    容易想到(Theta(qsqrt n))的枚举每一个因子的做法,然而正解是(Theta(qlog n))的。

    考虑每次除去一个素因子。还有判断函数可以这样写:

    inline void pd(int l,int a,int b){
          return make(a,b-l)==make(a+l,b);
    }
    

    这样写就能判断(l)是不是(S[a...b])的周期。

    我写完正解之后极限数据在本地要跑( ext{15s}),交上去评测机只跑了( ext{26ms}),我想打人。

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 1e9
    const int maxn=5e5+10;
    const int base=29;
    const int mod=1e8+9;
    int n,m,hs[maxn],pw[maxn];string s;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }int flag[maxn],tot;
    inline int make(int l,int r){
    	return (hs[r]-1ll*hs[l-1]*pw[r-l+1]%mod+mod)%mod;
    }int pri[maxn],p[maxn];
    inline bool pd(int l,int a,int b){return make(a,b-l)==make(a+l,b);}
    int main(){
    	freopen("loj2696.in","r",stdin);
    	freopen("loj2696.out","w",stdout);
    	n=read();cin>>s;
    	for(int i=1;i<=n;++i)
    		hs[i]=(1ll*hs[i-1]*base%mod+s[i-1]-'a'+1)%mod;
    	pw[0]=1;
    	for(int i=1;i<=n;++i)
    		pw[i]=1ll*pw[i-1]*base%mod;
    	for(int i=2;i<=n;i++){
    		if(!flag[i])pri[++tot]=i,p[i]=i;
    		for(int j=1;j<=tot&&pri[j]*i<=n;j++){
    			flag[i*pri[j]]=1;
    			p[i*pri[j]]=pri[j];
    			if(i%pri[j]==0)break;
    		}
    	}
    	m=read();
    	int x,y,len,z;
    	for(int i=1;i<=m;++i){
    		x=read(),y=read();len=y-x+1;
    		for(int j=len;j>1;j/=p[j])
    			if(pd(len/p[j],x,y))len/=p[j];
    		printf("%d
    ",len);
    	}
    	return 0;
    }
    

    #2697. 「POI2012」斐波那契表示法 Fibonacci Representation

    玄学贪心求证明!

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int maxn=2e5+10;
    const int mod=1e9+7;
    const ll N=4e17+10;
    ll n,m,f[maxn];
    inline ll read(){
    	ll x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    inline int divide(int l,int r,ll val){
    	int ans=1;
    	while(l<=r){
    		int mid=(l+r)>>1;
    		if(f[mid]<=val)ans=mid,l=mid+1;
    		else r=mid-1;
    	}
    	return ans;
    }
    int main(){
    	n=read();
    	f[1]=f[2]=1ll;
    	int t=3;
    	for(;(f[t]=f[t-1]+f[t-2])<N;t++);
    	while(n--){
    		m=read();
    		int cnt=0;
    		while(m){
    			cnt++;int p=divide(1,t,m);
    			m=min(m-f[p],f[p+1]-m);
    		}
    		printf("%d
    ",cnt);
    	}
    	return 0;
    }
    

    #2693. 「POI2012」比赛路线 Tour de Byteotia

    两端点都(>k)的边一定不会被删。

    所以先加入所有两端点(>k)的边,再拿剩下的边做一次( ext{Kruskal})即可。

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 1e9
    const int maxn=2e6+10;
    const int mod=1e9+7;
    int n,m,k;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    int fa[maxn];
    inline int find(int x){
    	if(fa[x]==x)return x;
    	return fa[x]=find(fa[x]);
    }
    int tot,a[maxn],b[maxn];
    int u[maxn],v[maxn];
    int main(){
    	n=read(),m=read(),k=read();
    	int x,y;
    	for(int i=1;i<=n;i++)fa[i]=i;
    	for(int i=1;i<=m;i++){
    		x=read(),y=read();
    		if(x>y)swap(x,y);
    		u[i]=x;v[i]=y;
    		if(x>k)fa[find(x)]=find(y);
    	}
    	for(int i=1;i<=m;i++){
    		x=u[i],y=v[i];
    		if(x>k)continue;
    		if(find(x)==find(y))
    			++tot,a[tot]=x,b[tot]=y;
    		else fa[find(x)]=find(y);
    	}
    	printf("%d
    ",tot);
    	for(int i=1;i<=tot;i++)
    		printf("%d %d
    ",a[i],b[i]);
    	return 0;
    }
    

    #2698. 「POI2012」超夸克 Squarks

    排序。考虑枚举(a_2+a_3)的位置。

    注意到(a_2+a_3)前面的一定是(a_1+a_2)(a_1+a_3)(a_1+a_4)……(a_1+a_{pos}),故(a_1)(a_{pos})的值都可以确定。

    已经确定的这些数会产生一些和,把这些和从序列中去掉后,剩下的第一个一定是(a_1+a_{pos+1}),故又可以知道(a_{pos+1})的值。

    发现比(a_2+a_3)小的只有可能是(a_1+a_2)(a_1+a_n),故此处复杂度(Theta(n)),总理论复杂度(Theta(n^3log n))

    实际跑得飞快。

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 1e9
    const int maxn=2e5+10;
    const int mod=1e9+7;
    int n,m,a[maxn];
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    map<int,int>sta,cnt,pre;
    int ans[301][301],tot,b[maxn];
    int main(){
    	n=read();m=n*(n-1)/2;
    	for(int i=1;i<=m;i++)a[i]=read();
    	for(int i=1;i<=m;i++)sta[a[i]]++;
    	sort(a+1,a+1+m);
    	for(int i=3;i<=n;i++){
    		int sum=(a[1]+a[2]+a[i])/2,flag=1;
    		b[1]=sum-a[i];b[2]=sum-a[2];b[3]=sum-a[1];
    		for(int j=4;j<=i;j++)b[j]=a[j-1]-b[1];
    		cnt.clear(),pre.clear();
    		for(int j=1;j<=i;j++){
    			for(int k=1;k<j;k++){
    				int x=b[j]+b[k];cnt[x]++;
    				if(cnt[x]>sta[x]){flag=0;break;}
    			}if(!flag)break;
    			pre[a[j]]++;
    		}if(!flag)continue;
    		for(int j=i+1,pos=i+1;j<=n;j++){
    			while(pre[a[pos]]<cnt[a[pos]])
    				pre[a[pos++]]++;
    			b[j]=a[pos]-b[1];
    			for(int k=1;k<j;k++){
    				int x=b[k]+b[j];cnt[x]++;
    				if(cnt[x]>sta[x]){flag=0;break;}
    			}if(!flag)continue;
    		}if(!flag)continue;flag=0;
    		for(int j=1;j<=n;j++)
    			flag|=(ans[tot][j]^b[j]);
    		if(flag)tot++;
    		for(int j=1;j<=n;j++)
    			ans[tot][j]=b[j];
    	}
    	printf("%d
    ",tot);
    	for(int i=1;i<=tot;i++){
    		for(int j=1;j<=n;j++)
    			printf("%d ",ans[i][j]);
    		puts("");
    	}
    	return 0;
    }
    

    #2700. 「POI2012」工资 Salaries

    思路挺妙。我们可以求出每个点最大取到的值,考虑转化问题为每个点有上限,能确定几个点。

    从小到大排序,直接处理即可。

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 1e9
    const int maxn=1e6+10;
    const int mod=1e9+7;
    int n,m,a[maxn],rt,vis[maxn],mx[maxn];
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    int beg[maxn],nex[maxn],to[maxn],e;
    inline void add(int x,int y){
    	e++;nex[e]=beg[x];
    	beg[x]=e;to[e]=y;
    }
    pair<int,int>b[maxn];
    inline void dfs(int x,int val){
    	if(!a[x])b[++m]=make_pair(val,x);
    	for(int i=beg[x];i;i=nex[i])
    		dfs(to[i],a[to[i]]?a[to[i]]:mx[val-1]);
    }
    int main(){
    	n=read();
    	for(int i=1,x;i<=n;i++){
    		x=read();a[i]=read();
    		if(x==i)rt=i;else add(x,i);
    		vis[a[i]]=1;
    	}
    	for(int i=1;i<=n;i++)
    		mx[i]=vis[i]?mx[i-1]:i;
    	dfs(rt,n);
    	sort(b+1,b+1+m);
    	for(int i=1,j=1,k=0;i<=n;i++){
    		if(vis[i]){k++;continue;}
    		int cnt=0;
    		while(b[j].first==i)cnt++,j++;
    		if(cnt==1&&j-1+k==i)
    			a[b[j-1].second]=i;
    	}
    	for(int i=1;i<=n;i++)
    		printf("%d
    ",a[i]);
    	return 0;
    }
    

    #2703. 「POI2012」仓库式商店 Warehouse Store

    直接反悔贪心即可。不会证明。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int maxn=3e5+10;
    const int mod=1e9+7;
    int n,m,ans[maxn];
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    int a[maxn],b[maxn];
    priority_queue<pair<int,int> >q;
    signed main(){
    	n=read();
    	for(int i=1;i<=n;i++)a[i]=read();
    	for(int i=1;i<=n;i++)b[i]=read();
    	for(int i=1,tot=0,t;i<=n;i++){
    		tot+=a[i];
    		if(tot>=b[i]){
    			m++;tot-=b[i];
    			q.push(make_pair(b[i],i));
    			continue;
    		}
    		if(q.empty())continue;
    		t=q.top().first;
    		if(b[i]<t){
    			q.pop();
    			q.push(make_pair(b[i],i));
    			tot+=t-b[i];
    		}
    	}
    	printf("%lld
    ",m);
    	for(int i=1;i<=m;i++){
    		ans[i]=q.top().second;
    		q.pop();
    	}
    	sort(ans+1,ans+1+m);
    	for(int i=1;i<=m;i++)
    		printf("%lld ",ans[i]);
    	return 0;
    }
    

    #2704. 「POI2012」前后缀 Prefixuffix

    不知道怎么想到的。问题要求将原串划分为( ext{ABCBA})的形式。

    考虑( ext{A})的长度为(i)( ext{B})的最大长度为(f_i),易证有(f_ileq f_{i+1}+2),故可以(Theta(n))求出(f)数组。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int maxn=1e6+10;
    const int mod=1e9+9;
    const int base=141;
    int n,hs[maxn],pw[maxn],f[maxn],ans;
    string s;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    inline int make(int r,int len){
    	return (hs[r]-hs[r-len]*pw[len]%mod+mod)%mod;
    }
    inline bool check(int r1,int r2,int len){
    	return make(r1,len)==make(r2,len);
    }
    signed main(){
    	n=read();cin>>s;
    	for(int i=1;i<=n;i++)
    		hs[i]=(hs[i-1]*base+s[i-1]-'a'+1)%mod;
    	pw[0]=1;for(int i=1;i<=n;i++)pw[i]=pw[i-1]*base%mod;
    	for(int i=n/2;i;i--){
    		f[i]=min(f[i+1]+2,n/2-i);
    		while(!check(i+f[i],n-i,f[i]))f[i]--;
    	}
    	for(int i=1;i<=n/2;i++)
    		if(check(i,n,i))ans=max(ans,i+f[i]);
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    #2702. 「POI2012」极简主义的安保 Minimalist Security

    考虑一个联通块,设一个点的值为(x),则其他所有点的值都可以用(x)表示。

    1. 若可以解出(x),直接计算贡献即可。

    2. 否则计算(x)的范围,每个点有(0leq xleq p_i),注意到整体是一个一次函数,则极值分别取端点即可。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    typedef long long ll;
    #define inf 1e9
    const int maxn=5e5+10;
    const int maxm=6e6+10;
    const int mod=1e9+7;
    int n,m,p[maxn],v[maxn];
    ll amx,amn;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    int beg[maxn],nex[maxm],to[maxm],w[maxm],e;
    inline void add(int x,int y,int z){
    	e++;nex[e]=beg[x];
    	beg[x]=e;to[e]=y;w[e]=z;
    }
    int vis[maxn],sta[maxn],top,xv;
    struct node{int k,b;}a[maxn];
    inline void dfs(int x){
    	sta[++top]=x;vis[x]=1;
    	for(int i=beg[x];i;i=nex[i]){
    		int t=to[i];
    		if(!vis[t]){
    			a[t].k=-a[x].k;
    			a[t].b=w[i]-a[x].b;
    			dfs(t);
    		}else if(a[x].k+a[t].k==0){
    			if(a[x].b+a[t].b!=w[i])puts("NIE"),exit(0);
    		}else xv=(w[i]-a[x].b-a[t].b)/(a[x].k+a[t].k);
    	}
    }
    signed main(){
    	n=read(),m=read();
    	for(int i=1;i<=n;i++)
    		p[i]=read();
    	int x,y,z;
    	for(int i=1;i<=m;i++){
    		x=read(),y=read(),z=read();
    		add(x,y,z),add(y,x,z);
    	}
    	for(int i=1;i<=n;i++){
    		if(vis[i])continue;
    		xv=inf,top=0;
    		a[i].k=1;dfs(i);
    		if(xv!=inf){
    			for(int j=1,t;j<=top;j++)
    				t=sta[j],v[t]=a[t].k*xv+a[t].b;
    			for(int j=1;j<=top;j++)
    				for(int k=beg[sta[j]];k;k=nex[k])
    					if(v[sta[j]]+v[to[k]]!=w[k])return puts("NIE"),0;
    			for(int j=1;j<=top;j++)
    				if(v[sta[j]]>p[sta[j]])return puts("NIE"),0;
    			for(int j=1,t;j<=top;j++)
    				t=sta[j],amn+=p[t]-v[t],amx+=p[t]-v[t];
    		}else{
    			int l=-inf,r=inf,ksum=0;ll bsum=0;
    			for(int j=1;j<=top;j++){
    				int t=sta[j];
    				ksum-=a[t].k;bsum+=p[t]-a[t].b;
    				if(a[t].k==1){
    					l=max(l,-a[t].b);
    					r=min(r,p[t]-a[t].b);
    				}else{
    					l=max(l,a[t].b-p[t]);
    					r=min(r,a[t].b);
    				}
    			}
    			if(l>r)return puts("NIE"),0;
    			if(ksum>=0)amn+=ksum*l+bsum,amx+=ksum*r+bsum;
    			else amn+=ksum*r+bsum,amx+=ksum*l+bsum;
    		}
    	}
    	printf("%lld %lld
    ",amn,amx);
    	return 0;
    }
    

    #2701. 「POI2012」找平地面 Leveling Ground

    太难了,先搁着,以后做。

    参考资料:zsy大佬的poi2012题解

  • 相关阅读:
    mac md5/base64 终端处理 及文件处理js
    ag(Silver Searcher)查找文件
    js压缩之uglify-js
    iReport Designer在mac下打不开
    mac新建批处理文件,双击启动.sh文件
    将本地文件夹添加到Git仓库
    vue2.X + HTML5 plus 拍照和调用设备相册 另附 图片转base64和压缩图片方法
    Vue3-js 学习笔记
    Vue2.x 常用功能和方法
    typescript 编译报错 不能用于索引类型
  • 原文地址:https://www.cnblogs.com/syzf2222/p/14393911.html
Copyright © 2020-2023  润新知