反思:
我考得最炸的一次
怎么说呢?简单的两个题0分,稍难(我还不敢说难,肯定又有人喷我)42分
前10分钟看T1,不会,觉得不可做,完全不可做,把它跳了
最后10分钟看T1,发现一个有点用的性质,仍然认为不可实现
0分
所以T1是什么样的难题呢
即使暴力也有60分,但我楞没想出来暴力怎么打
然后我就挂掉了
t2又是什么样难题
大多数人秒切一个小时切两道,
但这次考试给了我很大启迪,也正是这次考试我才开始使劲刚T1
其实大多数T1都是比较简单的,并没有想象中那么难,这次考试对我来说意义很大
(就在模拟测试21我也认为T1很难坚持刚其实T1还是很简单的)
count
题解
一共有多少种方案可以把这棵树分成大小相同的几块
题干简洁明了,
性质:我们如果能分成大小相同全为$size$大小的几块,那么只有一种方案分成大小全为$size$
有了这条性质我们就可以愉快的打了
枚举所有n的约数打了就$AC$了(还有不要暴力枚举约数,先根号n求一下约数)
实现,假设当前我们发现这个子树累计$size$达到了约数就剪掉这个枝条
若减不掉就累加到父亲上,如果父亲减不掉且$size$已经比当前枚举约数大了,那么当前方案不可行,否则方案$++$
例如我们枚举约数3,我们在3减不掉,5减不掉,累加到2,2判断size大了所以不可行
bool dfs(ll x,ll pre,ll num){ sz[x]=1; for(ll i=head[x];i;i=nxt[i]){ ll y=ver[i]; if(y==pre) continue; if(!dfs(y,x,num)) return 0; sz[x]+=sz[y]; if(sz[x]>num) return 0; } // printf("sz=%lld ",sz[x]); if(sz[x]==num) sz[x]=0; return 1; }
代码
#include<bits/stdc++.h> using namespace std; #define ll int #define A 2999989 ll sz[A],ver[A],nxt[A],head[A]; ll ans=2,tot=1,n,m; vector<ll> woshishabi; void add(ll x,ll y){ ver[++tot]=y,nxt[tot]=head[x],head[x]=tot; } inline ll read(){ ll x=0,f=1;char c=getchar(); while(!isdigit(c)){ if(c=='-') f=-1; c=getchar(); } while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); } return f*x; } bool dfs(ll x,ll pre,ll num){ sz[x]=1; for(ll i=head[x];i;i=nxt[i]){ ll y=ver[i]; if(y==pre) continue; if(!dfs(y,x,num)) return 0; sz[x]+=sz[y]; if(sz[x]>num) return 0; } // printf("sz=%lld ",sz[x]); if(sz[x]==num) sz[x]=0; return 1; } int main(){ n=read(); for(ll i=1,a,b;i<n;i++){ a=read(),b=read(); add(a,b);add(b,a); } for(ll i=2;i<=sqrt(n);i++){ if(n%i==0){ if(i*i==n) woshishabi.push_back(i); else woshishabi.push_back(i),woshishabi.push_back(n/i); } } for(ll i=0;i<woshishabi.size();i++){ if(dfs(1,0,woshishabi[i])){ ans++; } // printf("=%lld ans=%lld ",woshishabi[i],ans); } cout<<ans<<endl; }
dinner
题解
不错的题意转化
分成个数最少的环,每个环总权值最大的最小
最大的最小??
二分答案
一个很好的二分答案题,让我明白了我们枚举其实可以拿分块优化一下
暴力应该都会打吧
枚举圈的数量,这里讲一下$check$
我采取的是首先找到一个圈,找到最左可以到达的值,以及到达最左后到达右面节点,这已经$1$个圈了
每次枚举剩下的值,若当前符合直接返回,不符合最左指针$++$,右面指针跟着移动,进行操作知道最左达到$n+1$
这样一般过不了(然而我暴力$nian$标算了)我打法玄学
while(now<=tim){ tl--; now+=a[tl]; } now-=a[tl],tl++; while(now<=tim){ tr++; now+=a[tr]; } now-=a[tr],tr--; //一个完美的闭合回路 while(tl!=n+2) { cnt=2;tot=0; // printf("tl=%lld tr=%lld ",tl,tr); //除了当前满足的tl,tr之外的圈的另一半 for(LL j=tr+1;j<=tl+n-1;j++) { if(tot>tim)tot=a[j],cnt++; if(cnt>m){cnt=m+10;break;} } // printf("cnt=%lld ",cnt); if(cnt<=m)return 1; now-=a[tl];tl++; while(now<=tim){ tr++; now+=a[tr]; } now-=a[tr],tr--; } return 0; }
主要讲剪枝
就一句话特别简单
if(j+t<=tl+n-1&&sum[j+t]-sum[j-1]+tot<=tim){tot+=(sum[j+t]-sum[j-1]);j+=t;continue;}
能t加就加t,一句小的剪枝让你从$T60$分到$100$分,从$3000$-->$200$(虽然我暴力跑了$100$)
方法简单,
一定要掌握这种思想
代码
#include<bits/stdc++.h> using namespace std; #define LL long long #define A 1010101 LL a[A],sum[A]; LL n,m,ans,avg,mx=-1,t; LL check(LL tim){ LL now=0,tl=n+1,tr=n+1,tot,cnt=0; now=a[n+1]; // printf("now=%lld ",now); while(now<=tim){ tl--; now+=a[tl]; } now-=a[tl],tl++; while(now<=tim){ tr++; now+=a[tr]; } now-=a[tr],tr--; //一个完美的闭合回路 while(tl!=n+2) { cnt=2;tot=0; // printf("tl=%lld tr=%lld ",tl,tr); //除了当前满足的tl,tr之外的圈的另一半 for(LL j=tr+1;j<=tl+n-1;j++) { if(j+t<=tl+n-1&&sum[j+t]-sum[j-1]+tot<=tim){tot+=(sum[j+t]-sum[j-1]);j+=t;continue;} tot+=a[j]; if(tot>tim)tot=a[j],cnt++; if(cnt>m){cnt=m+10;break;} } // printf("cnt=%lld ",cnt); if(cnt<=m)return 1; now-=a[tl];tl++; while(now<=tim){ tr++; now+=a[tr]; } now-=a[tr],tr--; } return 0; } int main(){ scanf("%lld%lld",&n,&m); t=sqrt(n); for(LL i=1;i<=n;i++){ scanf("%lld",&a[i]); a[i+n]=a[i]; mx=max(mx,a[i]); }for(LL i=1;i<=2*n;i++) sum[i]=sum[i-1]+a[i]; LL l=mx,r=sum[n]; while(l<=r){ LL mid=(l+r)>>1; if(check(mid)) r=mid-1,ans=mid; else l=mid+1; } printf("%lld ",ans); }
chess
题解
知道了正解也难以实现打了$4$个小时,我最后还是颓了标程,然而刚看$10$秒就明白怎么做并用$10$分钟$AC$
首先我们要掌握一种科技最短路计数
然而敌军不能对方案造成影响,考虑缩边
那么题解中说缩边缩边,怎么缩啊
我尝试跑两遍$spfa$(伪缩边)然而只有$20$分
尝试$tarjan$(伪缩边)然而只有$0$分
尝试对拍小点全对,大点全错
好难实现,考虑每个点$dfs?$
能过?,能过最多每个点搜每个点一遍善用复杂度分析$2500^2$
那么$dfs$搜些什么,
既然敌军不能对方案造成影响,遇到敌军往下搜但不建边,遇到空格return并且建边
建单向边,这样我们就缩边了
很巧妙不是吗?
注意答案可能很大开0x7ffffffffffffffffffff
代码
#include<bits/stdc++.h> using namespace std; #define ll long long #define A 51000 ll head[A],nxt[A],ver[A],way[A],dis[A],G[51][51],mzz[51][51]; ll F[58][58]; ll qix,qiy,zhongx,zhongy; bool flag[A]; ll tot=0,n,m; ll id(ll x,ll y){ return (x-1)*m+y; } void jb(ll x,ll y){//建边 // printf("jbjbjbjbx=%lld y=%lld ",x,y); nxt[++tot]=head[x],head[x]=tot,ver[tot]=y; } const ll nowx[9]={0,2,2,1,-1,-2,-2,1,-1}; const ll nowy[9]={0,1,-1,2,2,1,-1,-2,-2}; void dfs(ll root,ll x,ll y){ G[x][y]=1; // printf("x=%lld y=%lld ",x,y); for(ll i=1;i<=8;i++){ ll x1=nowx[i]+x,y1=nowy[i]+y; // printf("x=%lld y=%lld x1=%lld y1=%lld ",x,y,x1,y1); if(x1<1||x1>n||y1<1||y1>m||G[x1][y1]) continue; if(F[x1][y1]==1) dfs(root,x1,y1); else G[x1][y1]=1,jb(root,mzz[x1][y1]); } } /*void spfa(ll w){ deque<ll>q; memset(dis,0x3f,sizeof(dis)); memset(flag,0,sizeof(flag)); dis[w]=0; q.push_back(w); while(!q.empty()){ ll x=q.front(); q.pop_front(); flag[x]=0; for(ll i=head[x];i;i=nxt[i]){ ll y=ver[i]; if(dis[y]>dis[x]+edge[i]){ if(edge[i]==0) choose[y]=x; dis[y]=dis[x]+edge[i]; // printf("x=%lld y=%lld dx=%lld dy=%lld ",x,y,dis[x],dis[y]); // if(x==59||y==59){ // printf("*********** "); // } if(!flag[y]){ q.push_back(y); flag[y]=1; } } } } }*/ void spfa2(ll w){ deque<ll>q; memset(dis,0x7f,sizeof(dis)); memset(flag,0,sizeof(flag)); dis[w]=0; q.push_back(w); while(!q.empty()){ ll x=q.front(); q.pop_front(); flag[x]=0; // printf("x=%lld ",x); for(ll i=head[x];i;i=nxt[i]){ ll y=ver[i]; if(dis[y]>dis[x]+1){ way[y]=way[x]; dis[y]=dis[x]+1; if(!flag[y]){ q.push_back(y); flag[y]=1; } } else if(dis[y]==dis[x]+1){ way[y]+=way[x]; } } } } int main(){ scanf("%lld%lld",&n,&m); for(ll i=1;i<=n;i++) for(ll j=1;j<=m;j++){ mzz[i][j]=id(i,j); // printf("mzz[%lld][%lld]=%lld ",i,j,mzz[i][j]); } for(ll i=1;i<=n;i++) for(ll j=1;j<=m;j++){ scanf("%lld",&F[i][j]); if(F[i][j]==3) qix=i,qiy=j; else if(F[i][j]==4) zhongx=i,zhongy=j; } for(ll i=1;i<=n;i++) for(ll j=1;j<=m;j++){ if(F[i][j]==0||F[i][j]==3){ memset(G,0,sizeof(G)); dfs(mzz[i][j],i,j); } } /* for(ll i=1;i<=n;i++) for(ll j=1;j<=m;j++){ if(F[i][j]==2) continue; for(ll k=1;k<=8;k++){ ll x1=i+nowx[k],y1=j+nowy[k]; ll idpre=id(i,j),idnow=id(x1,y1); if(x1<1||x1>n||y1<1||y1>m) continue; if(F[x1][y1]==2) continue; if(!G[idpre][idnow]){ if(F[x1][y1]==1||F[x1][y1]==4) jb(idpre,idnow,0),G[idpre][idnow]=1; else jb(idpre,idnow,1),G[idpre][idnow]=1; } } if(F[i][j]==3) qix=i,qiy=j; else if(F[i][j]==4) zhongx=i,zhongy=j; } */ way[mzz[qix][qiy]]=1; // printf("%lld %lld ",dis[id(zhongx,zhongy)],way[id(zhongx,zhongy)]); spfa2(mzz[qix][qiy]); if(dis[mzz[zhongx][zhongy]]>1e8) printf("-1 "); else printf("%lld %lld ",dis[mzz[zhongx][zhongy]]-1,way[mzz[zhongx][zhongy]]); }