考虑转化问题.
把边之间的禁止关系转化成点之间的.
还有一种思路.
发现每个边的出边和入边只能选一个.
所以可以选择固定一个点的出边/入边,然后删边判定就行了.
#include<bits/stdc++.h> using namespace std; namespace BSS { #define ll long long int #define ull unsigned ll #define lf double #define lbt(x) (x&(-x)) #define mp(x,y) make_pair(x,y) #define lb lower_bound #define ub upper_bound #define Fill(x,y) memset(x,y,sizeof x) #define Copy(x,y) memcpy(x,y,sizeof x) #define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout) inline ll read() { ll res=0; bool cit=1; char ch; while(!isdigit(ch=getchar())) if(ch=='-') cit=0; while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar(); return cit?res:-res; } } using namespace BSS; const ll N=3e6+21,mod=998244353; ll m,n,ans; ll fa[N],vis[N]; struct Graph{ ll ts; ll head[N]; struct I { ll u,v,col,nxt; } e[N<<1]; inline void add(ll u,ll v,ll opt){ e[++ts].u=u,e[ts].v=v,e[ts].nxt=head[u], head[u]=ts,e[ts].col=opt; } }A,B; inline ll find(ll x){ return x==fa[x] ? x : fa[x]=find(fa[x]); } inline ll ksm(ll a,ll b,ll c){ a%=c; ll res=1; for(;b;b>>=1,a=a*a%c) if(b&1) res=res*a%c; return res%c; } signed main(){ File(a); n=read(); ll u,v,a,b,c,d; A.ts=1; for(int i=1;i<=2*n;i++) u=read(),v=read(),A.add(u,v,1),A.add(v,u,0); for(int u=1;u<=n;u++){ a=A.head[u],b=A.e[a].nxt,c=A.e[b].nxt,d=A.e[c].nxt; if(A.e[a].col==A.e[b].col) B.add(a-(a&1),b-(b&1),0),B.add(c-(c&1),d-(d&1),0); else if(A.e[a].col==A.e[c].col) B.add(a-(a&1),c-(c&1),0),B.add(b-(b&1),d-(d&1),0); else if(A.e[a].col==A.e[d].col) B.add(a-(a&1),d-(d&1),0),B.add(b-(b&1),c-(c&1),0); } for(int i=2;i<=A.ts;i+=2) fa[i]=i; for(int i=1;i<=B.ts;i++){ u=B.e[i].u,v=B.e[i].v; if(find(u)!=find(v)) fa[find(u)]=find(v); } for(int i=2;i<=A.ts;i+=2) if(!vis[find(i)]) ans++,vis[find(i)]=1; printf("%lld\n",ksm(2,ans,mod)); exit(0); }
一开始就应该推性质而不是莽干的.
做不出来的时候思维就应该发散一下.
由于越取平均数答案越小,其实序列有一个最多只有两段的性质.
也就是说答案要么只有单增的一段,要么就是一段单增,一段单减.
#include<bits/stdc++.h> using namespace std; namespace BSS { #define ll long long int #define ull unsigned ll #define lf double #define lbt(x) (x&(-x)) #define mp(x,y) make_pair(x,y) #define lb lower_bound #define ub upper_bound #define Fill(x,y) memset(x,y,sizeof x) #define Copy(x,y) memcpy(x,y,sizeof x) #define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout) inline ll read() { ll res=0; bool cit=1; char ch; while(!isdigit(ch=getchar())) if(ch=='-') cit=0; while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar(); return cit?res:-res; } } using namespace BSS; const ll N=1e5+21; lf ans; ll m,n,cnt; ll val[N],lsh[N],ans1[N],ans2[N]; struct Bit_Array{ ll res; ll c[N<<2]; inline void update(ll x,ll w){ for(;x<=n;x+=lbt(x)) c[x]=max(c[x],w); } inline ll query(ll x){ res=0; for(;x>0;x&=(x-1)) res=max(res,c[x]); return res; } inline void clr(){ Fill(c,0); } }bit; signed main(){ File(b); n=read(); for(int i=1;i<=n;i++) lsh[i]=val[i]=read(); sort(lsh+1,lsh+1+n),cnt=unique(lsh+1,lsh+1+n)-lsh-1; for(int i=1;i<=n;i++){ val[i]=lb(lsh+1,lsh+1+cnt,val[i])-lsh; ans1[i]=bit.query(val[i]-1)+lsh[val[i]]; bit.update(val[i],ans1[i]); } bit.clr(); for(int i=n;i>=1;i--){ ans2[i]=bit.query(val[i]-1)+lsh[val[i]]; bit.update(val[i],ans2[i]); } for(int i=1;i<=n;i++) ans1[i]=max(ans1[i],ans1[i-1]); for(int i=n;i>=1;i--) ans2[i]=max(ans2[i],ans2[i+1]); for(int i=1;i<=n;i++){ ans=max(ans,1.0*ans1[i]); ans=max(ans,1.0*(ans1[i]+ans2[i+1])/2); } printf("%.3lf\n",ans); exit(0); }
很显然是构造题.
由于两点之间即可确定一条线.
所以可以转化成只让前两行和前两列被消成 \(0\).
#include<bits/stdc++.h> using namespace std; namespace BSS { #define ll long long int #define ull unsigned ll #define lf double #define lbt(x) (x&(-x)) #define mp(x,y) make_pair(x,y) #define lb lower_bound #define ub upper_bound #define Fill(x,y) memset(x,y,sizeof x) #define Copy(x,y) memcpy(x,y,sizeof x) #define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout) inline ll read() { ll res=0; bool cit=1; char ch; while(!isdigit(ch=getchar())) if(ch=='-') cit=0; while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar(); return cit?res:-res; } } using namespace BSS; const ll N=1e3+21; ll m,n,cntx,cnty,cntz; ll x[N],y[N],z[N*3]; ll w[N][N]; signed main(){ File(c); n=read(),m=read(); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ w[i][j]=read(); } } x[1]=w[2][2]-w[1][1],z[N]=-w[2][2]; for(int i=2;i<=n;i++) z[N+1-i]+=-x[i]-w[i][1],x[i+1]+=-(z[N+1-i]+w[i+1][2]); for(int j=2;j<=m;j++) z[N+j-1]+=-y[j]-x[1]-w[1][j],y[j+1]+=-(z[N+j-1]+w[2][j+1]); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++) if(w[i][j]+x[i]+y[j]+z[j-i+N]) puts("-1"),exit(0); } cout<<n+m+(m-1-(1-n)+1)<<endl; for(int i=1;i<=n;i++) cout<<1<<' '<<i<<' '<<x[i]<<endl; for(int j=1;j<=m;j++) cout<<2<<' '<<j<<' '<<y[j]<<endl; for(int i=1-n;i<=m-1;i++) cout<<3<<' '<<i<<' '<<z[N+i]<<endl; exit(0); }
没见过二维斜率优化,枯了.
考场上想了斜率优化,但是写的是一维的,发现这个东西很离奇,于是就死了.
不应该拘束于已经学过的东西.
#include<bits/stdc++.h> using namespace std; namespace BSS { #define ll long long int #define ull unsigned ll #define lf double #define lbt(x) (x&(-x)) #define mp(x,y) make_pair(x,y) #define lb lower_bound #define ub upper_bound #define Fill(x,y) memset(x,y,sizeof x) #define Copy(x,y) memcpy(x,y,sizeof x) #define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout) inline ll read() { ll res=0; bool cit=1; char ch; while(!isdigit(ch=getchar())) if(ch=='-') cit=0; while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar(); return cit?res:-res; } } using namespace BSS; const ll N=5e3+21; ll m,n,ans; ll val[N],stk[N],sum[N]; ll dp[N][N]; struct I { ll pre,id; } p[N]; inline bool comp(I i,I j){ return i.pre==j.pre ? i.id<j.id : i.pre<j.pre; } inline ll caly(ll j,ll k){ return dp[j][k]; } inline lf slope(ll j,ll ka,ll kb){ return sum[ka]==sum[kb] ? 1e15 : 1.0*(caly(j,ka)-caly(j,kb))/(sum[ka]-sum[kb]); } signed main(){ File(d); n=read(); ll l,r,id; for(int i=1;i<=n;i++){ val[i]=read(),p[i].pre=p[i-1].pre+val[i],p[i].id=i; sum[i]=p[i].pre; } sort(p+1,p+1+n,comp); for(int j=1;j<=n;j++){ l=1,r=0; for(int k=1;k<=n;k++){ id=p[k].id; if(id>=j) continue; while(l<r and slope(j,stk[r],stk[r-1])<=slope(j,id,stk[r])){ r--; } stk[++r]=id; } for(int i=n;i>=1;i--){ id=p[i].id; if(id<=j) continue; while(l<r and (slope(j,stk[l+1],stk[l])>=(sum[id]-sum[j]))){ l++; } dp[id][j]=max(caly(j,stk[l])+(sum[id]-sum[j])*(sum[j]-sum[stk[l]]),(sum[id]-sum[j])*sum[j]); } } for(int i=1;i<=n;i++){ ans=max(ans,dp[n][i]); } printf("%lld\n",ans); exit(0); }