NOIP2024(欢乐)加赛3
\(T1\) CF2033B Sakurako and Water \(100pts\)
-
枚举主对角线取 \(\max\) 即可。
点击查看代码
ll a[510][510]; int main() { ll t,n,ans=0,maxx,i,j,k,h; cin>>t; for(h=1;h<=t;h++) { cin>>n; ans=0; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { cin>>a[i][j]; } } for(k=-n+1;k<=n+1;k++) { maxx=0; for(i=1,j=i+k;i<=n;i++,j++) { if(i<=n&&1<=j&&j<=n&&a[i][j]<0) { maxx=max(maxx,-a[i][j]); } } ans+=maxx; } cout<<ans<<endl; } return 0; }
\(T2\) CF2025B Binomial Coefficients, Kind Of \(100pts\)
-
观察样例加打表可知, \(2^{[k \ne n] \times k}\) 即为所求。
- 已知递推式 \(f_{i,j}=\begin{cases} 1 & j=0 \lor j=n \\ f_{n,k-1}+f_{n-1,k-1} & j \in [1,n) \end{cases}\) ,省去 \(j=n\) 的状态后有 \(f_{i,j}=f_{i+1,j}\) 。
- \(f_{i,j}\) 能更新到的值只有 \(\begin{cases} f_{i,j+1}=f_{i+1,j+1}=2f_{i,j} \end{cases}\) ,故 \(2^{[k \ne n] \times k}\) 即为所求。
点击查看代码
const ll p=1000000007; ll n[100010],m[100010],C[1010][1010]; 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() { ll t,i; cin>>t; for(i=1;i<=t;i++) { cin>>n[i]; } for(i=1;i<=t;i++) { cin>>m[i]; if(m[i]==n[i]) { cout<<1<<endl; } else { cout<<qpow(2,m[i],p)<<endl; } } return 0; }
\(T3\) CF2030D QED's Favorite Permutation \(100pts\)
-
对于移动,我们可以无脑进行交换来保证移动,然后将中途交换的位置再交换回去。
-
通过手摸不难发现, \(p_{i}\) 能移动到 \(i\) 当且仅当 \(s_{\min(i,p_{i}) \sim \max(i,p_{i})}\) 中不含有
LR
子串。 -
反向考虑,即
LR
子串不被上述区间包含,差分判断即可。点击查看代码
ll a[200010],d[200010]; char s[200010]; int main() { ll t,n,m,x,sum,i,j; cin>>t; for(j=1;j<=t;j++) { cin>>n>>m; sum=0; for(i=1;i<=n;i++) { cin>>a[i]; d[min(a[i],i)]++; d[max(a[i],i)]--; } for(i=1;i<=n;i++) { d[i]+=d[i-1]; } cin>>(s+1); for(i=1;i<=n-1;i++) { if(s[i]=='L'&&s[i+1]=='R') { sum+=(d[i]!=0); } } for(i=1;i<=m;i++) { cin>>x; if(s[x]=='L') { s[x]='R'; if(x+1<=n&&s[x+1]=='R') { sum-=(d[x]!=0); } if(x-1>=1&&s[x-1]=='L') { sum+=(d[x-1]!=0); } } else { s[x]='L'; if(x+1<=n&&s[x+1]=='R') { sum+=(d[x]!=0); } if(x-1>=1&&s[x-1]=='L') { sum-=(d[x-1]!=0); } } if(sum!=0) { cout<<"No"<<endl; } else { cout<<"Yes"<<endl; } } for(i=1;i<=n;i++) { d[i]=0; } } return 0; }
\(T4\) CF2025E Card Game \(10pts\)
- 部分分
- \(10pts\) :输出样例。
\(T5\) CF1967D Long Way to be Non-decreasing \(16pts\)
-
部分分
- \(16pts\)
- 考虑从 \(i\) 向 \(b_{i}\) 连一条有向边,那么 \(i\) 能到达的点就是经过若干次操作后可以成为的值。
- 答案上界显然为 \(m\) ,考虑二分答案。
- \(check\) 时选令 \(a_{i}\) 走到 \(mid\) 步能到达的范围内不小于 \(a_{i-1}'\) 的数 \(a_{i}\) ,主席树空间开不下遂写了暴力。
点击查看代码
int a[1000010],b[1000010],vis[1000010],tot=0; vector<int>e[1000010],s[1000010]; void dfs(int x,int rt) { s[rt].push_back(x); vis[x]=tot; for(int i=0;i<e[x].size();i++) { if(vis[e[x][i]]!=tot) { dfs(e[x][i],rt); } } } bool check(int mid,int n,int m) { int last=0,minn; for(int i=1;i<=n;i++) { minn=0x7f7f7f7f; for(int j=0;j<s[a[i]].size()&&j<=mid;j++) { if(s[a[i]][j]>=last) { minn=min(minn,s[a[i]][j]); } } last=minn; if(last==0x7f7f7f7f) { return false; } } return true; } int main() { int testcase,n,m,l,r,mid,ans,i,j; scanf("%d",&testcase); for(j=1;j<=testcase;j++) { scanf("%d%d",&n,&m); for(i=1;i<=m;i++) { e[i].clear(); s[i].clear(); vis[i]=0; } for(i=1;i<=n;i++) { cin>>a[i]; } for(i=1;i<=m;i++) { cin>>b[i]; e[i].push_back(b[i]); } for(i=1;i<=m;i++) { tot++; dfs(i,i); } l=0; r=m; ans=-1; while(l<=r) { mid=(l+r)/2; if(check(mid,n,m)==true) { ans=mid; r=mid-1; } else { l=mid+1; } } printf("%d\n",ans); } return 0; }
- \(16pts\)
-
正解
\(T6\) CF2023D Many Games \(9pts\)
-
部分分
- \(7pts\) :爆搜。
- \(9pts\) :背包。
点击查看代码
总结
- \(T4\) 的部分分没来得及写。
- \(T5\) 以为最终连成的一个环,破环为链后分前后缀考虑,然后就口胡了个假的势能线段树维护在线二维数点。基本全场都在写 \(T5\) 。