12.1
闲话
- 详见 2024 NOIP 游记 12.1 。
做题纪要
12.2
闲话
- 详见 2024 NOIP 游记 12.2 。
做题纪要
12.3
闲话
- 在机房补 \(whk\) 。
做题纪要
luogu P9759 [COCI2022-2023#3] Bomboni
-
将原状态设计中 \(\mod k\) 一维改为与 \(k\) 的 \(\gcd\) 即可。
点击查看代码
const int p=998244353; int a[510][510],f[510][510][310],d[1000010],g[310],gd[510][510]; int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif int n,m,cnt=0,i,j,k; scanf("%d%d",&n,&m); for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { scanf("%d",&a[i][j]); if(a[i][j]!=-1) { a[i][j]=__gcd(a[i][j],m); } } } for(i=1;i<=m;i++) { if(m%i==0) { cnt++; d[i]=cnt; g[cnt]=i; } } for(i=1;i<=cnt;i++) { for(j=1;j<=cnt;j++) { gd[i][j]=d[__gcd(1ll*m,1ll*g[i]*g[j])]; } } f[1][1][d[a[1][1]]]=1; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { if(a[i][j]!=-1) { for(k=1;k<=cnt;k++) { if(i+1<=n&&a[i+1][j]!=-1) { f[i+1][j][gd[k][d[a[i+1][j]]]]=(f[i+1][j][gd[k][d[a[i+1][j]]]]+f[i][j][k])%p; } if(j+1<=n&&a[i][j+1]!=-1) { f[i][j+1][gd[k][d[a[i][j+1]]]]=(f[i][j+1][gd[k][d[a[i][j+1]]]]+f[i][j][k])%p; } } } } } printf("%d\n",f[n][n][cnt]); return 0; }
12.4
闲话
- 在机房补 \(whk\) 。
做题纪要
12.5
闲话
- 详见 2024 NOIP 游记 12.5 。
做题纪要
12.6
闲话
- 详见 2024 NOIP 游记 12.6 。
做题纪要
12.7
闲话
- 在机房补 \(whk\) 。
做题纪要
12.8
闲话
- 在机房补 \(whk\) 。
做题纪要
12.9
闲话
- 在机房补 \(whk\) 。
做题纪要
luogu P11361 [NOIP2024] 编辑字符串
-
直接将能相互交换的缩成一段然后开两个指针分别去扫,因需要处理两段的交需要较多的分讨。
-
贪心策略显然是能成功匹配的地方一定进行匹配,不妨枚举最优情况下答案的形态。
-
具体地,仍处理出每个字符所属于的极长连续段内 \(0/1\) 的个数。只用一个指针向右扫,若存在能成功匹配的就进行匹配,否则不让其成功匹配。正确性的话,可以考虑若本次未成功匹配但存在互换颜色后上次也没有进行成功匹配则一定不合法。
点击查看代码
int pos[3][100010],sum[3][100010][2]; char s[3][100010],t[3][100010]; int main() { // #define Isaac #ifdef Isaac freopen("edit.in","r",stdin); freopen("edit.out","w",stdout); #endif int testcase,n,ans=0,flag,i,j,k; scanf("%d",&testcase); for(k=1;k<=testcase;k++) { ans=0; scanf("%d%s%s%s%s",&n,s[1]+1,s[2]+1,t[1]+1,t[2]+1); memset(sum,0,sizeof(sum)); for(i=1;i<=n;i++) { for(j=1;j<=2;j++) { pos[j][i]=(t[j][i]=='1'&&t[j][i-1]=='1')?pos[j][i-1]:i; sum[j][pos[j][i]][0]+=(s[j][i]=='0'); sum[j][pos[j][i]][1]+=(s[j][i]=='1'); } } for(i=1;i<=n;i++) { for(flag=j=0;j<=1&&flag==0;j++) { if(sum[1][pos[1][i]][j]>=1&&sum[2][pos[2][i]][j]>=1) { ans++; flag=1; sum[1][pos[1][i]][j]--; sum[2][pos[2][i]][j]--; } } for(j=0;j<=1&&flag==0;j++) { if(sum[1][pos[1][i]][j]>=1&&sum[2][pos[2][i]][1^j]>=1) { flag=1; sum[1][pos[1][i]][j]--; sum[2][pos[2][i]][1^j]--; } } } printf("%d\n",ans); } return 0; }
559. 选择
-
观察到至多跳 \(O(\log)\) 遍,接着暴力即可。
点击查看代码
ll a[1000010]; int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif ll n,m,ans=0,sum=0,x,i,j,k; scanf("%lld",&n); m=log2(n)+1; for(i=1;i<=n;i++) { scanf("%lld",&a[i]); } for(i=0;i<=(1<<m)-1;i++) { x=1; sum=a[1]; for(j=0;j<=m;j++) { if((i>>j)&1) { x+=(1<<j); if(x>n) { break; } sum+=a[x]; } } ans=max(ans,sum); } printf("%lld\n",ans); return 0; }
560. 填空
-
找到最大子矩形后判断即可。
点击查看代码
ll h[1000010],l[1000010]; int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif ll t,n,m,p,q,w,a,b,i,j; scanf("%lld",&t); for(j=1;j<=t;j++) { a=b=0; scanf("%lld%lld%lld%lld%lld",&n,&m,&p,&q,&w); for(i=1;i<=p;i++) { scanf("%lld",&h[i]); a=max(a,h[i]-h[i-1]-1); } a=max(a,n-h[p]); for(i=1;i<=q;i++) { scanf("%lld",&l[i]); b=max(b,l[i]-l[i-1]-1); } b=max(b,m-l[q]); if(a*b>=w) { printf("Y\n"); } else { printf("N\n"); } } return 0; }
561. 计算
-
二维前缀和后二分答案。
点击查看代码
int sum[510][510],x[510],y[510]; int query(int x1,int y1,int x2,int y2) { return sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1]; } bool check(int mid,int n,int m) { int maxx=0; for(int i=1;i<=m;i++) { maxx=max(maxx,query(max(x[i]-mid,1),max(y[i]-mid,1),min(x[i]+mid,n),min(y[i]+mid,n))); } return 2*maxx>=m; } int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif int n,m,l=0,r,ans=0,mid,i,j; cin>>n>>m; for(i=1;i<=m;i++) { cin>>x[i]>>y[i]; sum[x[i]][y[i]]++; } for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]; } } r=n/2; while(l<=r) { mid=(l+r)/2; if(check(mid,n,m)==true) { r=mid-1; ans=2*mid+1; } else { l=mid+1; } } cout<<ans<<endl; return 0; }
12.10
闲话
- 在机房补 \(whk\) 。
做题纪要
12.11
闲话
- 在机房补 \(whk\) 。
做题纪要
525. 雷
-
以 \(-z\) 为边权求单源最短路得到比率后高精模拟加法。
点击查看代码
struct node { ll nxt,to,w; }e[400010]; ll head[400010],dis[400010],vis[400010],a[400010],ans[400010],cnt=0; void add(ll u,ll v,ll w) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; e[cnt].w=w; head[u]=cnt; } void spfa(ll s) { memset(dis,0x3f,sizeof(dis)); memset(vis,0,sizeof(vis)); queue<ll>q; q.push(s); dis[s]=0; vis[s]=1; while(q.empty()==0) { ll x=q.front(); vis[x]=0; q.pop(); for(ll i=head[x];i!=0;i=e[i].nxt) { if(dis[e[i].to]>dis[x]+e[i].w) { dis[e[i].to]=dis[x]+e[i].w; if(vis[e[i].to]==0) { q.push(e[i].to); vis[e[i].to]=1; } } } } } int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif ll n,m,u,v,w,i; cin>>n>>m; for(i=1;i<=n;i++) { cin>>a[i]; } for(i=1;i<=m;i++) { cin>>u>>v>>w; add(u,v,-w); } spfa(1); for(i=1;i<=n;i++) { if(dis[i]+30>=0) { ans[dis[i]+30]+=a[i]; } } ans[0]=20000; for(i=1;i<=20000;i++) { ans[i+1]+=ans[i]/10; ans[i]%=10; } if(ans[23]>=5) { ans[24]++; for(i=24;i<=20000;i++) { ans[i+1]+=ans[i]/10; ans[i]%=10; } } while(ans[0]>=31&&ans[ans[0]]==0) { ans[0]--; } for(i=ans[0];i>=30;i--) { cout<<ans[i]; } cout<<"."; for(i=29;i>=24;i--) { cout<<ans[i]; } return 0; }
12.12
闲话
- 在机房补 \(whk\) 。
做题纪要
51Nod 1202.子序列个数
-
设 \(f_{i}\) 表示 \([1,i]\) 中本质不同子序列的个数,状态转移方程为 \(f_{i}=\begin{cases} 2f_{i-1}-f_{last_{a_{i}-1}} & last_{a_{i}} \ne 0 \\ 2f_{i-1}+1 & last_{a_{i}}=0 \end{cases}\) 。
-
视题目要求决定是否要加上空串的贡献。
点击查看代码
const ll p=1000000007; ll f[1000010],last[1000010],a[1000010]; int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif ll n,i; cin>>n; for(i=1;i<=n;i++) { cin>>a[i]; if(last[a[i]]!=0) { f[i]=(2*f[i-1]-f[last[a[i]]-1]%p+p)%p; } else { f[i]=(2*f[i-1]+1)%p; } last[a[i]]=i; } cout<<(f[n]+1)%p<<endl; return 0; }
369. 稳稳的拼三角形
-
排序后肯定是连续三个一起选。考虑一次匹配失败后最小的数的值域至少除以 \(2\) ,故只保留前 \(\log\) 大进行判断。计算保留个数时应参考斐波那契的构造方式使得区间长度 \(\ge 45\) 个数时一定有解。
-
线段树上归并排序维护即可。
点击查看代码
int a[100010]; struct SMT { struct SegmentTree { vector<int>val; SegmentTree operator + (const SegmentTree &another) { SegmentTree tmp; int x=0,y=0; while(x<val.size()&&y<another.val.size()) { if(val[x]>another.val[y]) { tmp.val.push_back(val[x]); x++; } else { tmp.val.push_back(another.val[y]); y++; } } while(x<val.size()) { tmp.val.push_back(val[x]); x++; } while(y<another.val.size()) { tmp.val.push_back(another.val[y]); y++; } while(tmp.val.size()>=45) { tmp.val.pop_back(); } return tmp; } }tree[400010],ans; #define lson(rt) (rt<<1) #define rson(rt) (rt<<1|1) void pushup(int rt) { tree[rt]=tree[lson(rt)]+tree[rson(rt)]; } void build(int rt,int l,int r) { if(l==r) { tree[rt].val.push_back(a[l]); return; } int mid=(l+r)/2; build(lson(rt),l,mid); build(rson(rt),mid+1,r); pushup(rt); } void update(int rt,int l,int r,int pos,int val) { if(l==r) { tree[rt].val[0]=val; return; } int mid=(l+r)/2; if(pos<=mid) { update(lson(rt),l,mid,pos,val); } else { update(rson(rt),mid+1,r,pos,val); } pushup(rt); } void query(int rt,int l,int r,int x,int y) { if(x<=l&&r<=y) { ans=ans+tree[rt]; return; } int mid=(l+r)/2; if(x<=mid) { query(lson(rt),l,mid,x,y); } if(y>mid) { query(rson(rt),mid+1,r,x,y); } } int ask(int l,int r,int n) { ans.val.clear(); query(1,1,n,l,r); for(int i=0;i+2<ans.val.size();i++) { if(ans.val[i]<ans.val[i+1]+ans.val[i+2]) { return ans.val[i]+ans.val[i+1]+ans.val[i+2]; } } return 0; } }T; int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif int n,q,pd,l,r,i; cin>>n>>q; for(i=1;i<=n;i++) { cin>>a[i]; } T.build(1,1,n); for(i=1;i<=q;i++) { cin>>pd>>l>>r; if(pd==1) { T.update(1,1,n,l,r); } else { cout<<T.ask(l,r,n)<<endl; } } return 0; }
12.13
闲话
- 在机房补 \(whk\) 。
做题纪要
12.14
闲话
- 在机房补 \(whk\) 。
做题纪要
12.15
闲话
做题纪要
luogu B4060 位运算 1
-
基础位运算。
点击查看代码
int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif ll a,b,k; cin>>a>>b>>k; cout<<(a&b)<<endl; cout<<(a|b)<<endl; cout<<(a^b)<<endl; cout<<(~a)<<endl; cout<<(a<<k)<<endl; cout<<(a>>k)<<endl; return 0; }
luogu B4061 位运算 2
-
基础位运算。
点击查看代码
int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif ll a,b; cin>>a>>b; cout<<(a<<b)<<endl; cout<<(a>>b)<<endl; cout<<((a>>b)&1)<<endl; cout<<(a^(((a>>b)&1)<<b))<<endl; cout<<(a|(1<<b))<<endl; cout<<(a^(1<<b))<<endl; return 0; }
luogu P11362 [NOIP2024] 遗失的赋值
-
先判掉无解的情况,然后将 \(\{ c \}\) 排序并去重。考虑将答案分成若干段分别统计方案数然后再乘起来。
-
对于 \([c_{i},c_{i+1})\) 间的答案,考虑正难则反,用总方案数 \(v^{2(c_{i+1}-c_{i})}\) 减去不合法的方案数。
-
由题目限制,不合法方案数只可能来自二元限制与一元限制的冲突,即 \(a_{c_{i}}=d_{c_{i}},a_{c_{i}+1}=b_{c_{i}},a_{c_{i}+2}=b_{c_{i}+1},\dots ,a_{c_{i+1}-1}=b_{c_{i+1}-2},b_{c_{i+1}-1} \ne d_{c_{i+1}}\) 。其中 \(a_{c_{i}},b_{c_{i+1}-1}\) 的取值受到一定限制,故不合法方案数为 \((v-1)v^{2(c_{i+1}-c_{i}-1)}\) 。
-
类似地,由于 \([1,c_{1}),[c_{m},n)\) 不会产生不合法方案,故其贡献分别为 \(v^{2(c_{i}-1)},v^{2(n-c_{m})}\) 。
点击查看代码
const ll p=1000000007; pair<ll,ll>c[100010]; ll qpow(ll a,ll b,ll p) { ll ans=1; while(b) { if(b&1) { ans=ans*a%p; } b>>=1; a=a*a%p; } return ans; } int main() { // #define Isaac #ifdef Isaac freopen("assign.in","r",stdin); freopen("assign.out","w",stdout); #endif ll t,n,m,v,ans=0,i,j; scanf("%lld",&t); for(j=1;j<=t;j++) { scanf("%lld%lld%lld",&n,&m,&v); for(i=1;i<=m;i++) { scanf("%lld%lld",&c[i].first,&c[i].second); } sort(c+1,c+1+m); ans=qpow(v,2*(c[1].first-1),p)*qpow(v,2*(n-c[m].first),p)%p; for(i=2;i<=m;i++) { if(c[i].first==c[i-1].first) { ans*=(c[i].second==c[i-1].second); } else { ans=ans*(qpow(v,2*(c[i].first-c[i-1].first),p)-(v-1)*qpow(v,c[i].first-c[i-1].first-1,p)%p+p)%p; } } printf("%lld\n",ans); } return 0; }
12.16
闲话
- 在机房补 \(whk\) 。
做题纪要
12.17
闲话
做题纪要
luogu P10799 「CZOI-R1」三角形与树
-
和 369. 稳稳的拼三角形 一样套个树剖即可。
点击查看代码
struct node { ll nxt,to; }e[200010]; ll head[200010],fa[200010],siz[200010],dep[200010],son[200010],dfn[200010],top[200010],a[100010],n,cnt=0,tot=0; vector<ll>tmp; void add(ll u,ll v) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } void dfs1(ll x,ll father) { siz[x]=1; fa[x]=father; dep[x]=dep[father]+1; for(ll i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=father) { dfs1(e[i].to,x); siz[x]+=siz[e[i].to]; son[x]=(siz[e[i].to]>siz[son[x]])?e[i].to:son[x]; } } } void dfs2(ll x,ll id) { top[x]=id; tot++; dfn[x]=tot; if(son[x]!=0) { dfs2(son[x],id); for(ll i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=fa[x]&&e[i].to!=son[x]) { dfs2(e[i].to,e[i].to); } } } } struct BIT { ll c[100010]; ll lowbit(ll x) { return (x&(-x)); } void add(ll n,ll x,ll val) { for(ll i=x;i<=n;i+=lowbit(i)) { c[i]^=val; } } void update(ll l,ll r,ll val) { add(n,l,val); add(n,r+1,val); } ll getsum(ll x) { ll ans=0; for(ll i=x;i>=1;i-=lowbit(i)) { ans^=c[i]; } return ans; } }T; void update(ll u,ll v,ll w) { while(top[u]!=top[v]) { if(dep[top[u]]>dep[top[v]]) { T.update(dfn[top[u]],dfn[u],w); u=fa[top[u]]; } else { T.update(dfn[top[v]],dfn[v],w); v=fa[top[v]]; } } if(dep[u]<dep[v]) { T.update(dfn[u],dfn[v],w); } else { T.update(dfn[v],dfn[u],w); } } ll lca(ll u,ll v) { while(top[u]!=top[v]) { if(dep[top[u]]>dep[top[v]]) { u=fa[top[u]]; } else { v=fa[top[v]]; } } return dep[u]<dep[v]?u:v; } ll query(ll u,ll v) { ll rt=lca(u,v); if(dep[u]+dep[v]-2*dep[rt]>=47) { return 1; } tmp.clear(); tmp.push_back(T.getsum(dfn[rt])); while(u!=rt) { tmp.push_back(T.getsum(dfn[u])); u=fa[u]; } while(v!=rt) { tmp.push_back(T.getsum(dfn[v])); v=fa[v]; } sort(tmp.begin(),tmp.end()); for(ll i=0;i+2<tmp.size();i++) { if(tmp[i]+tmp[i+1]>tmp[i+2]) { return 1; } } return 0; } int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif ll q,u,v,w,pd,i; cin>>n>>q; for(i=1;i<=n;i++) { cin>>a[i]; } for(i=1;i<=n-1;i++) { cin>>u>>v; add(u,v); add(v,u); } dfs1(1,0); dfs2(1,1); for(i=1;i<=n;i++) { T.update(dfn[i],dfn[i],a[i]); } for(i=1;i<=q;i++) { cin>>pd>>u>>v; if(pd==1) { cin>>w; update(u,v,w); } else { cout<<query(u,v); } } return 0; }
CF1991F Triangle Formation
-
选取的两个三角形排序后不交是容易处理的,难点在于相交的情况。
-
不妨取连续六个一起选然后判断即可。
点击查看代码
int a[100010]; vector<int>b,pos,tmp; int check() { sort(pos.begin(),pos.end()); for(int i=1;i<=4;i++) { for(int j=i+1;j<=5;j++) { if(pos[0]+pos[i]>pos[j]) { tmp.clear(); for(int k=1;k<=5;k++) { if(k!=i&&k!=j) { tmp.push_back(pos[k]); } } if(tmp[0]+tmp[1]>tmp[2]) { return 1; } } } } return 0; } int ask(int l,int r) { if(r-l+1>=48) { return 1; } b.clear(); pos.clear(); for(int i=l;i<=r;i++) { b.push_back(a[i]); } sort(b.begin(),b.end()); for(int i=0;i+2<b.size();i++) { if(b[i]+b[i+1]>b[i+2]) { pos.push_back(i); } } if(pos.size()>=2&&pos.back()-pos.front()>=3) { return 1; } for(int i=0;i+5<b.size();i++) { pos.clear(); for(int j=i;j<=i+5;j++) { pos.push_back(b[j]); } if(check()==1) { return 1; } } return 0; } int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif int n,q,l,r,i; scanf("%d%d",&n,&q); for(i=1;i<=n;i++) { scanf("%d",&a[i]); } for(i=1;i<=q;i++) { scanf("%d%d",&l,&r); if(ask(l,r)==1) { printf("YES\n"); } else { printf("NO\n"); } } return 0; }
[ABC129F] Takahashi's Basics in Education and Learning
- 同 luogu P3216 [HNOI2011] 数学作业 ,矩阵快速幂加速。