这两次考试都挂了不少分,也学到了很多东西。
52 T1 常数写大正解T成暴力
T2 数组越界70->50又由于我的智障操作最后一秒50->20
53 T2 逆推打成正推100->21
T3 暴力56pts,错解57pts,机智的我交了暴力,还把数组开小了57->43。
1.虽然不同算法的理论复杂度是一样的,但是常数真的很重要!map常数很大!
2.在不确定自己打的是对的时候,不要在最后时刻交代码。
3.期望逆着推,其实不是期望,对于最优决策来说,要么枚举所有决策,
判断优劣,要么先逆着算出所有的情况的答案,寻找决策(记忆化搜索)
4.在代码过不了对拍的时候,一定要认真对待暴力。
5.矩阵快速幂某种程度上是说:x[i][j]表示j转移到i的系数。
6.记得测一下极限数据。
T1 平均数
sb题(谁正解T成暴力谁sb)
1 #include<cstdio> 2 #define N 100005 3 using namespace std; 4 int a[N],n,k; 5 long long sum[N],ans; 6 double tmp[N],q[N]; 7 inline int read() 8 { 9 int x=0;char c=getchar(); 10 while(c<'0'||c>'9')c=getchar(); 11 while(c>='0'&&c<='9')x=x*10+c-48,c=getchar(); 12 return x; 13 } 14 void solve(int l,int r) 15 { 16 if(l==r)return ; 17 int mid=l+r>>1; 18 solve(l,mid),solve(mid+1,r); 19 int pl=l,pr=mid+1,tot=l-1; 20 while(pl<=mid&&pr<=r) 21 { 22 if(tmp[pr]<=tmp[pl]) ans+=(mid-pl+1),q[++tot]=tmp[pr++]; 23 else q[++tot]=tmp[pl++]; 24 } 25 while(pl<=mid) q[++tot]=tmp[pl],pl++; 26 while(pr<=r) q[++tot]=tmp[pr],pr++; 27 for(register int i=l;i<=r;i++) tmp[i]=q[i]; 28 return ; 29 } 30 inline bool check(double x) 31 { 32 tmp[1]=0;ans=0; 33 for(register int i=1;i<=n;++i) 34 tmp[i+1]=sum[i]-i*x; 35 solve(1,n+1); 36 return ans<k; 37 } 38 inline double _min(double a,double b){return a<b?a:b;} 39 inline double _max(double a,double b){return a>b?a:b;} 40 int main() 41 { 42 double l=0x7f7f7f7f,r=0; 43 n=read(),k=read(); 44 for(register int i=1;i<=n;++i)a[i]=read(),l=_min(l,1.0*a[i]),r=_max(r,1.0*a[i]),sum[i]=sum[i-1]+a[i]; 45 while(r-l>1e-5) 46 { 47 double mid=(l+r)/2;//printf("%lf",mid); 48 if(check(mid))l=mid; 49 else r=mid; 50 } 51 printf("%.4lf ",l); 52 return 0; 53 }
T2 涂色游戏
我打的很麻烦。
1 #include<cstdio> 2 #include<cstring> 3 #define int long long 4 using namespace std; 5 const int mod=998244353; 6 int C[105][105],dp[105],g[105][105],fx[105][105][105],ed[105],n,m,p,q; 7 struct M{ 8 int x[105][105]; 9 friend M operator * (const M a,const M b) 10 { 11 M c; memset(c.x,0,sizeof c.x); 12 for(int i=1;i<=p;i++) 13 for(int j=1;j<=p;j++) 14 for(int k=1;k<=p;k++) 15 (c.x[i][j]+=a.x[i][k]*b.x[k][j]%mod)%=mod; 16 return c; 17 } 18 void clear() 19 { 20 for(int i=1;i<=p;i++)x[i][i]=1; 21 } 22 void out(){for(int i=1;i<=p;i++,puts(""))for(int j=1;j<=p;j++)cout<<x[i][j]<<' ';} 23 }ans,now; 24 inline void qpower(int b) 25 { 26 ans.clear();//ans.out(); 27 for(;b;b>>=1,now=now*now) if(b&1)ans=ans*now; 28 return ; 29 } 30 signed main() 31 { 32 scanf("%lld%lld%lld%lld",&n,&m,&p,&q); C[1][0]=C[1][1]=C[0][0]=g[1][1]=1; 33 for(int i=2;i<=100;C[i++][0]=1) 34 for(int j=1;j<=i;j++) 35 C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod, 36 g[j][i]=(g[j-1][i-1]*j%mod+g[j][i-1]*j%mod)%mod; 37 for(int i=0;i<=p;i++) 38 for(int j=0;j<=p;j++) 39 for(int k=0;k<=j;k++) 40 fx[i][j][k]=(fx[i][j][k-1]+C[i][k]*C[p-i][j-k]%mod)%mod; 41 for(int i=1;i<=p;i++)dp[i]=C[p][i]*g[i][n]%mod; 42 for(int j=1;j<=p;j++) 43 for(int k=q-j;k<=p;k++) 44 { 45 if(k<1) continue; 46 if(k<q)now.x[j][k]=(C[p][j]-fx[p-k][j][q-k-1]+mod)%mod*g[j][n]%mod; 47 else now.x[j][k]=C[p][j]*g[j][n]%mod; 48 } 49 qpower(m-1); 50 for(int i=1;i<=p;i++) 51 for(int j=1;j<=p;j++) 52 (ed[i]+=ans.x[i][j]*dp[j]%mod)%=mod; 53 int ans=0; 54 for(int j=1;j<=p;j++) (ans+=ed[j])%=mod; 55 printf("%lld ",ans); 56 }
T3 序列
开一棵主席树维护询问区间,把每个区间拆成两个前缀询问,第一次询问统计每个点的贡献,后面再直接弄即可。
1 #include<cstdio> 2 #include<iostream> 3 #include<vector> 4 #define N 100005 5 using namespace std; 6 vector<int>cs[2][N]; 7 int rt[2][N],a[N]; 8 long long ans; 9 inline int read() 10 { 11 int x=0;char c=getchar(); 12 while(c<'0'||c>'9')c=getchar(); 13 while(c>='0'&&c<='9')x=x*10+c-48,c=getchar(); 14 return x; 15 } 16 struct Segtree{ 17 int ls[N<<6],rs[N<<6],s[N<<6],tot; 18 void insert(int &k,int l,int r,int pos,int pre) 19 { 20 if(!k)k=++tot; 21 if(l==r) 22 { 23 if(!s[k])s[k]=s[pre]+1; 24 else s[k]++; 25 return ; 26 } 27 int mid=l+r>>1; 28 if(pos<=mid) 29 { 30 if(!rs[k])rs[k]=rs[pre]; 31 if(ls[k]==ls[pre])ls[k]=++tot; 32 insert(ls[k],l,mid,pos,ls[pre]); 33 } 34 else 35 { 36 if(!ls[k])ls[k]=ls[pre]; 37 if(rs[k]==rs[pre])rs[k]=++tot; 38 insert(rs[k],mid+1,r,pos,rs[pre]); 39 } 40 s[k]=s[ls[k]]+s[rs[k]]; 41 } 42 int query(int k,int l,int r,int ll,int rr) 43 { 44 if(l>=ll&&r<=rr) {return s[k];} 45 int mid=l+r>>1; 46 return (ll<=mid?query(ls[k],l,mid,ll,rr):0)+(rr>mid?query(rs[k],mid+1,r,ll,rr):0); 47 } 48 }T; 49 int main() 50 { 51 int n=read(),m=read(),q=read(); 52 for(int i=1;i<=n;i++)a[i]=read(); 53 for(int i=1;i<=m;i++) 54 { 55 int l=read(),r=read(),x=read(); 56 cs[0][x].push_back(l-1),cs[1][x].push_back(r); 57 } 58 for(int i=1;i<=n;i++) 59 { 60 if(!cs[0][i].size()) rt[0][i]=rt[0][i-1],rt[1][i]=rt[1][i-1]; 61 for(int j=0;j<cs[0][i].size();j++) T.insert(rt[0][i],0,n,cs[0][i][j],rt[0][i-1]); 62 for(int j=0;j<cs[1][i].size();j++) T.insert(rt[1][i],0,n,cs[1][i][j],rt[1][i-1]); 63 } 64 for(int i=1;i<=n;i++) 65 ans+=T.query(rt[1][a[i]],0,n,i,n)-T.query(rt[0][a[i]],0,n,i,n); 66 printf("%lld ",ans); 67 while(q--) 68 { 69 int p=read()^ans,v=read()^ans; 70 if(v<a[p]) 71 ans-=T.query(rt[1][a[p]],0,n,p,n),ans+=T.query(rt[1][v],0,n,p,n), 72 ans+=T.query(rt[0][a[p]],0,n,p,n),ans-=T.query(rt[0][v],0,n,p,n); 73 else if(v^a[p]) 74 ans+=T.query(rt[1][v],0,n,p,n),ans-=T.query(rt[1][a[p]],0,n,p,n), 75 ans-=T.query(rt[0][v],0,n,p,n),ans+=T.query(rt[0][a[p]],0,n,p,n); 76 a[p]=v; 77 printf("%lld ",ans); 78 } 79 return 0; 80 }
Lockey大神打的比较简单的打法:维护对每个位置的询问,差分+主席树维护前缀。
具体来说:对于一个询问Q(l,r,x),先在l处把x询问++,在r+1处x询问--。
一个一个插入主席树,再询问前缀,就能得到某点的询问,值得借鉴。
还有$O(nlogn^2)$的线段树加vector,不再多说。
T1 u
差分题,只有2*n条斜线,直接差分维护。
1 #include<cstdio> 2 #define N 2005 3 #define int long long 4 using namespace std; 5 int cf[N][N],gt[N][N],tot,fir[N][N],n; 6 inline int _min(int a,int b){return a<b?a:b;} 7 inline int read() 8 { 9 int x=0;char c=getchar(); 10 while(c>'9'||c<'0')c=getchar(); 11 while(c>='0'&&c<='9')x=x*10+c-48,c=getchar(); 12 return x; 13 } 14 void Get(int x,int y) 15 { 16 fir[x][y]=cf[x][y]; 17 if(x+1>0&&y+1<=n) 18 { 19 cf[x+1][y+1]+=cf[x][y]; 20 Get(x+1,y+1); 21 } 22 } 23 signed main() 24 { 25 n=read(); 26 int q=read(),ans=0; 27 while(q--) 28 { 29 int r=read(),c=read(),l=read(),s=read(); 30 gt[r][c]+=s; 31 gt[_min(r+l,n+1)][c]-=s; 32 cf[r][c+1]-=s; 33 cf[_min(r+l,n+1)][_min(c+l+1,n+1)]+=s; 34 } 35 for(int i=1;i<=n;i++)Get(1,i); 36 for(int i=2;i<=n;i++)Get(i,1); 37 for(int i=1;i<=n;i++) 38 for(int j=1;j<=n;j++) 39 { 40 gt[j][i]+=gt[j-1][i]; 41 fir[j][i]+=gt[j][i]; 42 } 43 for(int i=1;i<=n;i++) 44 for(int j=1;j<=n;j++) 45 { 46 fir[i][j]+=fir[i][j-1]; 47 ans^=fir[i][j]; 48 } 49 printf("%lld ",ans); 50 return 0; 51 }
T2 v
典型状压题,记忆化一下AC,状态数我并不会证。
1 #include<cstdio> 2 #define mod 2333333 3 using namespace std; 4 struct Hushmap{ 5 int cnt,head[2400000],to[mod+1],nxt[mod+1]; 6 double id[mod+1]; 7 void insert(long long x,double p) 8 { 9 int k=x%mod; 10 to[++cnt]=x,nxt[cnt]=head[k],id[cnt]=p,head[k]=cnt; 11 } 12 double find(long long x) 13 { 14 int k=x%mod; 15 for(int i=head[k];i;i=nxt[i]) if(to[i]==x) return id[i]; 16 return -1; 17 } 18 }H[31]; 19 int n,k; 20 char s[105]; 21 inline int gank(int x,int w) 22 { 23 int tmp=x&((1<<w)-1); 24 x>>=(w+1);x<<=w;tmp|=x; 25 return tmp; 26 } 27 inline double _max(double a,double b) 28 { 29 return a>b?a:b; 30 } 31 double dfs(int now,int st) 32 { 33 if(now==k+1) return 0; 34 double jc=H[now].find(st); 35 if(jc>=0)return jc; 36 double tmp=0; 37 for(int i=1;i<=n-now+1;i++) 38 { 39 int ot=n-now+2-i; 40 double a,b; 41 a=dfs(now+1,gank(st,i-1))+((st>>i-1)&1); 42 b=dfs(now+1,gank(st,ot-1))+((st>>ot-1)&1); 43 tmp+=_max(a,b)/(n-now+1); 44 } 45 H[now].insert(st,tmp); 46 return tmp; 47 } 48 int main() 49 { 50 double ans=0;int st=0; 51 scanf("%d%d",&n,&k); 52 scanf("%s",s+1); 53 for(int i=1;i<=n;i++) 54 { 55 int tmp=0; 56 if(s[i]=='W')tmp=1; 57 else tmp=0; 58 st|=(tmp<<i-1); 59 } 60 printf("%.8lf ",dfs(1,st)); 61 return 0; 62 }
T3 w
暴力/乱搞可以搞到80分(数据水)
正解是二元组DP,由于路径条数不好维护,维护奇数点,合并子树,分情况讨论即可。
1 #include<bits/stdc++.h> 2 #define N 200005 3 #define INF 200001 4 #define mp make_pair 5 #define fir first 6 #define sec second 7 #define P pair<int,int> 8 using namespace std; 9 int to[N<<1],nxt[N<<1],head[N],cnt=1,col[N<<1],toc[N<<1],ans=0; 10 pair<int,int>dp[N][2]; 11 inline void Add(int u,int v,int fr,int ty){to[++cnt]=v,nxt[cnt]=head[u],head[u]=cnt,col[cnt]=fr,toc[cnt]=ty;} 12 inline int read() 13 { 14 int x=0;char c=getchar(); 15 while(c>'9'||c<'0')c=getchar(); 16 while(c>='0'&&c<='9')x=x*10+c-48,c=getchar(); 17 return x; 18 } 19 inline int _max(int a,int b){return a>b?a:b;} 20 inline int _min(int a,int b){return a<b?a:b;} 21 inline P add(P a,P b) 22 { 23 return mp(a.fir+b.fir,a.sec+b.sec); 24 } 25 void dfs(int x,int pre) 26 { 27 P w1=mp(INF,INF),w2=mp(0,0); 28 for(int i=head[x];i;i=nxt[i]) 29 { 30 if(i==(pre^1))continue; 31 int y=to[i]; 32 dfs(y,i); 33 P tmp1=w1,tmp2=w2; 34 w1=min(add(tmp1,dp[y][0]),add(tmp2,dp[y][1])); 35 w2=min(add(tmp1,dp[y][1]),add(tmp2,dp[y][0])); 36 } 37 if(col[pre]==(toc[pre]^1)) dp[x][0]=mp(INF,INF),dp[x][1]=min(add(w1,mp(0,1)),add(w2,mp(1,1))); 38 else if(col[pre]==toc[pre]) dp[x][1]=mp(INF,INF),dp[x][0]=min(add(w1,mp(1,0)),w2); 39 else dp[x][1]=min(add(w1,mp(0,1)),add(w2,mp(1,1))),dp[x][0]=min(add(w1,mp(1,0)),w2); 40 return ; 41 } 42 int main() 43 { 44 int n=read(); 45 for(int i=1,a,b,c,d;i<n;i++) 46 { 47 a=read(),b=read(),c=read()+2,d=read()+2,Add(a,b,c,d),Add(b,a,c,d); 48 if(c==(d^1))ans++; 49 } 50 dfs(1,0); 51 printf("%d %d ",dp[1][0].fir/2,dp[1][0].sec); 52 }