2024/9/24
P1314 聪明的质检员
来翻历届真题,发现这道题还没过。
首先瞪眼可知 \(y\) 具有单调性,所以想到二分。
先不考虑 \(check\) 函数,把过程写了。
这道题和常规二分不同,因为要考虑绝对值,所以需要对 \(mid\) 分正负两种情况考虑。
然后在纸上画了画,基本定型以后开始写。写了 15min 以后发现挂了,动态查错 20min 发现我 \(l\) 赋值成了 \(ch(mid)\),人才啊。
对于 \(check\) 函数的话我想到了教主的魔法,但是看了看数据范围好像只有 70。于是想到每次要查询的数是唯一的,所以完全可以离线以后 \(\mathcal{O}(n)\) 预处理前缀和。
然后就过了。
点击查看代码
#include<bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
#define int long long
using namespace std;
// using namespace __gnu_pbds;
// tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> tr;//从小到大
// int findnum(int k){auto it=tr.find_by_order(k-1);return ((it!=tr.end())?(*it):1e9+7);}//查元素
// int findrank(int x){return tr.order_of_key(x)+1;}//查排名
// static char buf[100000],*pa=buf,*pd=buf;
// #define gc pa==pd&&(pd=(pa=buf)+fread(buf,1,100000,stdin),pa==pd)?EOF:*pa++
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int maxn=3e6;
const int mod=998244353;
const int inf=1e9+7;
int n,m,s;
struct no
{
int w,v;
}a[maxn];
struct Ask
{
int l,r;
}q[maxn];
int sum1[maxn],sum2[maxn];
int ch(int x)
{
for(int i=1;i<=n;i++)
{
if(a[i].w>=x)sum1[i]=sum1[i-1]+1,sum2[i]=sum2[i-1]+a[i].v;
else sum1[i]=sum1[i-1],sum2[i]=sum2[i-1];
}
int ans=0;
for(int i=1;i<=m;i++)
{
int l=q[i].l,r=q[i].r;
ans=(ans+(sum2[r]-sum2[l-1])*(sum1[r]-sum1[l-1]));
}
return ans;
}
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
cin>>n>>m>>s;
for(int i=1;i<=n;i++)a[i]={read(),read()};
for(int i=1;i<=m;i++)q[i]={read(),read()};
int l=0,r=2e6,mid;
int ans=inf;
// for(int i=1;i<=10000;i++)ans=min(ans,abs(ch(i)-s));
// cout<<ans<<endl;
// return 0;
while(l<r)
{
mid=(l+r)>>1;
int del=ch(mid)-s;
if(del==0)break;
if(del>0)
{
int pre=ch(mid-1)-s,nxt=ch(mid+1)-s;
if(pre==0){mid=pre;break;}
if(nxt==0){mid=nxt;break;}
if(pre>0&&nxt>0){l=mid+1;continue;}
if(pre>0&&nxt<0){mid=(-nxt>del?mid:mid+1);break;}
}
else if(del<0)
{
int pre=ch(mid-1)-s,nxt=ch(mid+1)-s;
if(pre==0){mid=pre;break;}
if(nxt==0){mid=nxt;break;}
if(pre<0&&nxt<0){r=mid-1;continue;}
if(pre>0&&nxt<0){mid=(pre>-del?mid:mid-1);break;}
}
// cout<<l<<' '<<r<<endl;
}
cout<<abs(ch(mid)-s);
return 0;
}
P2129 L 国的战斗续之多路出击
很水的绿题。
模拟的话会超时。
然后想到一句著名的话“如果大山不能走向穆罕默德,那么穆罕默德可以走向大山。”
于是每次操作直接平移坐标系即可。
点击查看代码
#include<bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
#define int long long
using namespace std;
// using namespace __gnu_pbds;
// tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> tr;//从小到大
// int findnum(int k){auto it=tr.find_by_order(k-1);return ((it!=tr.end())?(*it):1e9+7);}//查元素
// int findrank(int x){return tr.order_of_key(x)+1;}//查排名
// static char buf[100000],*pa=buf,*pd=buf;
// #define gc pa==pd&&(pd=(pa=buf)+fread(buf,1,100000,stdin),pa==pd)?EOF:*pa++
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int maxn=6e5;
const int mod=998244353;
const int inf=1e9+7;
struct no
{
int x,y;
}t[maxn];
int a[maxn],b[maxn];
int n,m;
char c[maxn];
int sx=1,sy=1,tx,ty;
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
cin>>n>>m;
for(int i=1;i<=n;i++)t[i]={read(),read()};
for(int i=1;i<=m;i++)
{
cin>>c[i];
if(c[i]=='m'){a[i]=read();b[i]=read();}
}
for(int i=m;i>=1;i--)
{
if(c[i]=='y')sy*=-1,ty*=-1;
else if(c[i]=='x')sx*=-1,tx*=-1;
else if(c[i]=='m')tx+=a[i],ty+=b[i];
}
for(int i=1;i<=n;i++)printf("%lld %lld\n",t[i].x*sx+tx,t[i].y*sy+ty);
return 0;
}
P2212 [USACO14MAR] Watering the Fields S
按照题意建图以后跑 MST,然后一遍过了。
P10460 防线
第一眼看题上说 <10^8 以为能暴力。
很有用的思想。
根据题意数列中只有一个奇数。我们可以根据只有一个奇数的数列和为奇数这个性质来判断这个数字是否在某个数列中。
于是可以用二分查找实现这个过程。
那么对于 \(check\) 函数,我们现在需要实现查找数列和的功能。
有一个小学公式: \(项数=\frac{末项-首项}{公差}+1\),然后对于每个等差数列都做一次即可。
一遍过!
点击查看代码
#include<bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
#define int long long
using namespace std;
// using namespace __gnu_pbds;
// tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> tr;//从小到大
// int findnum(int k){auto it=tr.find_by_order(k-1);return ((it!=tr.end())?(*it):1e9+7);}//查元素
// int findrank(int x){return tr.order_of_key(x)+1;}//查排名
// static char buf[100000],*pa=buf,*pd=buf;
// #define gc pa==pd&&(pd=(pa=buf)+fread(buf,1,100000,stdin),pa==pd)?EOF:*pa++
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int maxn=2e6;
const int mod=998244353;
const int inf=1e9+7;
int T;
int n;
struct no
{
int s,e,d;
}a[maxn];
int l,r;
int sum(int x)
{
int num=0;
for(int i=1;i<=n;i++)
{
if(a[i].s>x)continue;
num+=(min(x,a[i].e)-a[i].s)/a[i].d+1;
}
return num;
}
bool ch(int x,int y)
{
return ((sum(y)-sum(x-1))&1);
}
void Main()
{
n=read();
for(int i=1;i<=n;i++)a[i]={read(),read(),read()},l=min(l,a[i].s),r=max(r,a[i].e);
if(!ch(l,r))return puts("There's no weakness."),void();int ans=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(ch(l,mid))r=mid-1,ans=mid;
else l=mid+1;
}
cout<<ans<<' '<<sum(ans)-sum(ans-1)<<endl;
}
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
T=read();
while(T--)Main();
return 0;
}
AT_abc204_e [ABC204E] Rush Hour 2
变形的 dijkstra。
先思考什么情况下需要等待以及等待多长时间最优。我们把题目上的计算方法按照当前的时间 \(t\) 和通过所需的时间 \(f(t)\) 列个函数关系:
根据高一的数学知识可得这个函数是有最值的。
于是我们得到初步结论:最短路的时候比较当前时间和上面求出来的东西,如果当前时间已经在其之后,那么根据图象发现等待是不优的,所以正常转移。否则我们直接等到出现最小值的时刻再走就行了。
因为涉及到浮点数运算,所以需要注意精度问题。
一开始的时候发现无解判错了,怎么改都改不过,于是写了个并查集(我好菜)。
点击查看代码
#include<bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
#define int long long
using namespace std;
// using namespace __gnu_pbds;
// tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> tr;//从小到大
// int findnum(int k){auto it=tr.find_by_order(k-1);return ((it!=tr.end())?(*it):1e9+7);}//查元素
// int findrank(int x){return tr.order_of_key(x)+1;}//查排名
// static char buf[100000],*pa=buf,*pd=buf;
// #define gc pa==pd&&(pd=(pa=buf)+fread(buf,1,100000,stdin),pa==pd)?EOF:*pa++
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int maxn=6e5+100;
const int inf=998244353;
const int mod=1e9+7;
int n,m;
struct no
{
int y,c,d;
};
vector<no> G[maxn];
struct dij
{
int y,d;
inline friend bool operator < (dij x,dij y)
{
return x.d>y.d;
}
};
int dis[maxn];
bool vis[maxn];
void dijkstra()
{
memset(dis,0x3f,sizeof dis);
priority_queue<dij> q;
q.push({1,0});dis[1]=0;
while(!q.empty())
{
int u=q.top().y;
int t=q.top().d;
q.pop();
if(vis[u]) continue;
vis[u]=1;
for(auto i : G[u])
{
int y=i.y,c=i.c,d=i.d,ti;
int mi=round(sqrt(d))-1;
if(t<=mi)ti=mi;else ti=t;
if(dis[y]>ti+c+d/(ti+1))
{
dis[y]=ti+c+d/(ti+1);
if(!vis[y])
q.push({y,dis[y]});
}
}
}
}
int fa[maxn];
int gf(int x){return fa[x]==x?x:fa[x]=gf(fa[x]);}
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
cin>>n>>m;
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++)
{
int x=read(),y=read(),c=read(),d=read();
G[x].push_back({y,c,d});
G[y].push_back({x,c,d});
int fx=gf(x),fy=gf(y);
if(fx!=fy)fa[fx]=fy;
}
if(gf(1)!=gf(n))return 0*puts("-1");
dijkstra();
cout<<dis[n];
return 0;
}
P8312 [COCI2021-2022#4] Autobus
\(n\) 很小,所以果断考虑 Floyd。
因为这个 \(k\) 的限制,所以去思考该算法的本质,发现每次更新的时候直接用原来的边去更新就行了。
因为初值的问题卡了我 10min。
点击查看代码
#include<bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
#define int long long
using namespace std;
// using namespace __gnu_pbds;
// tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> tr;//从小到大
// int findnum(int k){auto it=tr.find_by_order(k-1);return ((it!=tr.end())?(*it):1e9+7);}//查元素
// int findrank(int x){return tr.order_of_key(x)+1;}//查排名
// static char buf[100000],*pa=buf,*pd=buf;
// #define gc pa==pd&&(pd=(pa=buf)+fread(buf,1,100000,stdin),pa==pd)?EOF:*pa++
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int maxn=6e6+100;
const int inf=998244353;
const int mod=1e9+7;
int n,m;
int dp[2000][2000],la[2000][2000],a[2000][2000];
int k,Q;
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
a[i][j]=1e9+7;
}
}
for(int i=1;i<=m;i++)
{
int x=read(),y=read(),z=read();
a[x][y]=min(a[x][y],z);
}
cin>>k>>Q;
k=min(k,n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dp[i][j]=la[i][j]=a[i][j];
}
}
for(int qw=2;qw<=k;qw++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dp[i][j]=la[i][j];
}
}
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dp[i][j]=min(dp[i][j],la[i][k]+a[k][j]);
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
la[i][j]=dp[i][j];
}
}
}
while(Q--)
{
int x=read(),y=read();
if(x==y)puts("0");
else if(dp[x][y]==1e9+7)puts("-1");
else printf("%lld\n",dp[x][y]);
}
return 0;
}
P7996 [WFOI - 01] 硬币(coin)
想到方差的基本性质:\(S(a*k)=S(a)*k^2\)。
于是我们可以计算原方差,然后公式一推得到答案。
由于可恶的精度误差,所以需要在答案附近浮动找答案。
这一行文字骗了我 4 发。
点击查看代码
#include<bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
#define int long long
using namespace std;
// using namespace __gnu_pbds;
// tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> tr;//从小到大
// int findnum(int k){auto it=tr.find_by_order(k-1);return ((it!=tr.end())?(*it):1e9+7);}//查元素
// int findrank(int x){return tr.order_of_key(x)+1;}//查排名
// static char buf[100000],*pa=buf,*pd=buf;
// #define gc pa==pd&&(pd=(pa=buf)+fread(buf,1,100000,stdin),pa==pd)?EOF:*pa++
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int maxn=7e6+100;
const int inf=998244353;
const int mod=1e9+7;
int n,k;
double sum,s;
int a[maxn];
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
cin>>n>>k;
for(int i=1;i<=n;i++)a[i]=read(),sum+=a[i];
sum/=(n*1.0);
for(int i=1;i<=n;i++)s+=(a[i]*1.0-sum)*(a[i]*1.0-sum);
s/=(n*1.0);
if(s==0.0)return puts("No answer!"),0;
int x=sqrt(k/s);double mi=6e18;
for(int i=max(1ll,x-2);i<=x+2;i++)
{
if(fabs(s*i*i*1.0-1.0*k)<mi)
{
mi=fabs(s*i*i*1.0-1.0*k);
x=i;
}
}
cout<<x;
return 0;
}
P8074 [COCI2009-2010#7] SVEMIR
之前模拟赛的一道题改了一下。
建图的结论还记得,然后正常建图以后跑一遍 MST 就行了。
代码死畅。
点击查看代码
#include<bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
#define int long long
using namespace std;
// using namespace __gnu_pbds;
// tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> tr;//从小到大
// int findnum(int k){auto it=tr.find_by_order(k-1);return ((it!=tr.end())?(*it):1e9+7);}//查元素
// int findrank(int x){return tr.order_of_key(x)+1;}//查排名
// static char buf[100000],*pa=buf,*pd=buf;
// #define gc pa==pd&&(pd=(pa=buf)+fread(buf,1,100000,stdin),pa==pd)?EOF:*pa++
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int maxn=1e6+100;
const int inf=998244353;
const int mod=1e9+7;
int n;
struct no
{
int x,y,z,id;
}a[maxn];
struct edge
{
int y,v;
};
vector<edge> G[maxn];
struct init
{
int x,y,z;
inline friend bool operator < (init x,init y)
{
return x.z<y.z;
}
}e[maxn];
int tot=0;
int fa[maxn];
int gf(int x){return fa[x]==x?x:fa[x]=gf(fa[x]);}
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
cin>>n;
for(int i=1;i<=n;i++)a[i]={read(),read(),read(),i};
sort(a+1,a+n+1,[](no x,no y){
return x.x<y.x||x.x==y.x&&x.y<y.y||x.x==y.x&&x.y==y.y&&x.z<y.z;
});
for(int i=1;i<n;i++)
{
int x=a[i].id,y=a[i+1].id,v=abs(a[i].x-a[i+1].x);
e[++tot]={x,y,v};
}
sort(a+1,a+n+1,[](no x,no y){
return x.y<y.y||x.y==y.y&&x.x<y.x||x.x==y.x&&x.y==y.y&&x.z<y.z;
});
for(int i=1;i<n;i++)
{
int x=a[i].id,y=a[i+1].id,v=abs(a[i].y-a[i+1].y);
e[++tot]={x,y,v};
}
sort(a+1,a+n+1,[](no x,no y){
return x.z<y.z||x.z==y.z&&x.x<y.x||x.z==y.z&&x.x==y.x&&x.y<y.y;
});
for(int i=1;i<n;i++)
{
int x=a[i].id,y=a[i+1].id,v=abs(a[i].z-a[i+1].z);
e[++tot]={x,y,v};
}
sort(e+1,e+tot+1);
for(int i=1;i<=n;i++)fa[i]=i;
int ans=0,cnt=0;
for(int i=1;i<=tot;i++)
{
int fx=e[i].x,fy=e[i].y;
fx=gf(fx);fy=gf(fy);
if(fx!=fy)
{
fa[fx]=fy;
ans+=e[i].z;
if(++cnt==n-1)
{
cout<<ans;
break;
}
}
}
return 0;
}