总结
T1
考场上很快想出了正解,并打出了代码,没什么问题
T2
考场上很快就打出了正解,但是由于精度问题,导致失分
T3
考场上没有想到解法,打了个部分分,但是挂0
T4
考场上打了个部分分,哪全了
题解
T1
不难发现,修改的方式一定如下:
- 确定分界线
- 分界线以左的
B
改成A
- 分界线以右的
A
改成B
枚举分界线,预处理前缀 B
的个数,后缀 A
的个数即可
代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=1e6+5;
int a[maxn],b[maxn];
signed main()
{freopen("string.in","r",stdin);freopen("string.out","w",stdout);ios::sync_with_stdio(0);cin.tie(0); cout.tie(0);string s;cin>>s;int n=s.size(),ans=inf;s=' '+s;for(int i=1;i<=n;i++) a[i]=a[i-1]+(s[i]=='B');for(int i=n;i>=1;i--) b[i]=b[i+1]+(s[i]=='A');for(int i=1;i<=n;i++) ans=min({ans,b[i]+a[i-1],a[i]+b[i+1]});cout<<ans;return 0;
}
T2
令我想骂人的题面
由于题面过于不是人看难懂,在重说一下:
有 \(n\) 个人,每个人有一个恒定的速度和初始位置,求让所有人到一个点时,到底最晚的人最早到的时间
考虑二分答案,二分最晚的人到的时间,那么每个人在规定的时间内跑的距离一定是一个区间(大不了原地等)看是否存在一个点,使得所有人都能到,有就往小找,并记录答案,没有就往大找即可
十年OI一场空,精度不够见祖宗
代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=2e5+5;
const double eps=1e-6;
int x[maxn],v[maxn],n;
double l[maxn],r[maxn];
bool check(double tmp)
{for(int i=1;i<=n;i++) l[i]=x[i]-v[i]*tmp*1.0,r[i]=x[i]+v[i]*tmp*1.0;double lt=0,rt=inf;for(int i=1;i<=n;i++) lt=max(lt,l[i]),rt=min(rt,r[i]);return rt-lt>=eps;
}
signed main()
{freopen("meeting.in","r",stdin);freopen("meeting.out","w",stdout);ios::sync_with_stdio(0);cin.tie(0);cin>>n;for(int i=1;i<=n;i++) cin>>x[i];for(int i=1;i<=n;i++) cin>>v[i];double l=0,r=1e9,ans=inf;while(r-l>eps){double mid=(l+r)/2;if(check(mid)==0) l=mid;else ans=mid,r=mid;}printf("%.5lf",ans);return 0;
}
T3
考虑将题目弱化一下,变成不能建道路,那么此时就是先判连通性,即那个点能到那个点,在枚举一个点,看有那些点满足两个点能互相到的,统计后取最大即可
现在考虑原题,不难发现:如果我建了一条边的反边,那么就相当于将两点合起来,那么接下来同上即可
代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=2000+5,maxm=40005;
vector<int> g[maxn];
int vis[maxn],ans=-inf,n,m,f[maxn][maxn],u[maxm],v[maxm];
void dfs(int x,int s)
{f[s][x]=1;for(auto to:g[x]) if(!f[s][to]) dfs(to,s);
}
signed main()
{freopen("travel.in","r",stdin);freopen("travel.out","w",stdout);ios::sync_with_stdio(0);cin.tie(0); cout.tie(0);cin>>n>>m;for(int i=1;i<=m;i++){cin>>u[i]>>v[i];g[u[i]].push_back(v[i]);}for(int i=1;i<=n;i++) dfs(i,i);for(int x=1;x<=m;x++){int i=u[x],j=v[x],sum=0;for(int k=1;k<=n;k++) if((f[i][k]||f[j][k])&&(f[k][j]||f[k][i])) sum++;ans=max(ans,sum);}if(!m) ans=1;cout<<ans;return 0;
}
T4
先考虑 \(O(t^4)\) 的做法:
对于一给正方形,只要三个信息就能得到,即:上边的位置和左,右边的位置
还有一个观察:题目求的正方形的左上角一定卡在障碍物或边界上
于是,在四个角加障碍物,枚举三边在判合法即可
\(O(t^3)\) 的做法
发现,其实我只要左,上边的位置即可,右,下边可以在判合法找到,于是枚举上,左边即可
代码(\(O(t^3)\))
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=2e5+5;
int x[maxn],y[maxn],dx[maxn],dy[maxn];
signed main()
{freopen("discover.in","r",stdin);freopen("discover.out","w",stdout);ios::sync_with_stdio(0);cin.tie(0); cout.tie(0);int n,t,ans=0;cin>>n>>t;for(int i=1;i<=t;i++) cin>>dx[i]>>dy[i],x[++x[0]]=dx[i]+1,y[++y[0]]=dy[i]+1;x[++x[0]]=1,y[++y[0]]=1;for(int i=1;i<=x[0];i++){for(int j=1;j<=y[0];j++){int a=x[i],b=y[j],sum=min(n-a+1,n-b+1);for(int k=1;k<=t;k++){if(dx[k]>=a&&dy[k]>=b) sum=min(sum,max(dx[k]-a,dy[k]-b));}ans=max(ans,sum);}}cout<<ans;return 0;
}
T5
考虑40分的做法:
发现以前做过类似的题目,不难发现一个值的贡献是 \(C_a^b\) 的,又通过提示卢卡斯定理得 \(C_n^m \mod 2=(n\& m=m)\)
故求二进制子集即可
100分的做法
不难发现:如果知道了某一行,那么后面的行无需看第1行,直接看那一行即可,故预处理前512行即可,后续同上
代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=1e5+5;
int a[512][maxn];
int f(int x,int y)
{if(x<512) return a[x][y];else{int len=1<<(int)log2(x);return f(x-len,y)^f(x-len,y+len);}
}
signed main()
{freopen("xor.in","r",stdin);freopen("xor.out","w",stdout);ios::sync_with_stdio(0);cin.tie(0); cout.tie(0);int n,q;cin>>n>>q;for(int i=0;i<n;i++) cin>>a[0][i];for(int i=1;i<512;i++) for(int j=0;j<n-i;j++) a[i][j]=a[i-1][j]^a[i-1][j+1];while(q--){int x,y;cin>>x>>y;cout<<f(x,y)<<endl;}return 0;
}