noip模拟40[双指针被抛弃了....]
noip模拟40 solutions
怎么说呢,我这两天用单调指针用的非常的顺手
第一题证都没证就单调指针去了,导致我抱零了
所以我以后用之前一定要证一下,
关于我做题老是想不到正解这件事,我已经不纠结了,因为我完全可以乱搞出奇迹
因为第二题我乱搞+卡时,搞到了70pts
T1 送花
这个就是枚举右端点,对左区间进行更新,这个有得天独厚的优势
因为一旦出现重复的东西,我就直接不要这个贡献了
在线段树上的操作就是对上上次出现的到上次出现的区间减去贡献
在上次出现到这次出现的区间内加上贡献
AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=1e6+5;
int n,m,c[N];
ll d[N];
struct XDS{
#define ls x<<1
#define rs x<<1|1
ll now[N*4],laz[N*4];
void pushup(int x){
now[x]=max(now[ls],now[rs]);
return ;
}
void pushdown(int x){
//cout<<x<<endl;
if(!laz[x])return ;
laz[ls]+=laz[x];
laz[rs]+=laz[x];
now[ls]+=laz[x];
now[rs]+=laz[x];
laz[x]=0;
return ;
}
void ins(int x,int l,int r,int ql,int qr,ll v){
//cout<<x<<" "<<l<<" "<<r<<" "<<ql<<" "<<qr<<endl;
if(ql>r||qr<l||ql>qr)return ;
if(ql<=l&&r<=qr){
now[x]+=v;laz[x]+=v;
return ;
}
pushdown(x);
int mid=l+r>>1;
if(ql<=mid)ins(ls,l,mid,ql,qr,v);
if(qr>mid)ins(rs,mid+1,r,ql,qr,v);
pushup(x);
return ;
}
#undef ls
#undef rs
}xds;
int pre[N],prx[N];
ll ans;
signed main(){
scanf("%d%d",&n,&m);
for(re i=1;i<=n;i++)scanf("%d",&c[i]);
for(re i=1;i<=m;i++)scanf("%lld",&d[i]);
for(re i=1;i<=n;i++){
xds.ins(1,1,n,prx[c[i]]+1,pre[c[i]],-d[c[i]]);
xds.ins(1,1,n,pre[c[i]]+1,i,d[c[i]]);
prx[c[i]]=pre[c[i]];
pre[c[i]]=i;
ans=max(ans,xds.now[1]);
}
printf("%lld",ans);
}
T2 星空
这就是我考场出奇迹的题,直接乱搞得到70pts
具体是这样做的,我一眼看上去,这好像是个最短路诶
最短路的话,直接dij那不就是最好的选择嘛????
我直接把每一对点的距离放到队列里面,额,好像是魔改dij
然后每次提取队头,从这两个端点分别向外扩展n个点,得到新的距离,再放到队列中
这样的话,保守估计,复杂度应该是\(\mathcal{O(n^3log^3n)}\)的
然后我觉得这样肯定会T ,所以就加上了一句话
int tim=clock();
if(clock()-tim>800000)break;
然后就成功的卡到了70pts,但是这个是有正确性的,如果数组可以开出来,就能A
因为每次都是找最短的来更新
70pts
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=1e5+5;
struct node{
int x,y,dis;
node(){}
node(int a,int b,int c){
x=a;y=b;dis=c;
}
bool operator < (node a)const{
return dis>a.dis;
}
};
priority_queue<node> q;
int n,dit[6005][6005],ans,sum;
struct pot{
int x,y;
pot(){}
}sca[N];
bool vis[6005][6005];
signed main(){
//cout<<((sizeof(vis)+sizeof(dit))>>20)<<endl;
int tim=clock();
scanf("%d",&n);
for(re i=1;i<=n;i++)
scanf("%d%d",&sca[i].x,&sca[i].y);
memset(dit,0x3f,sizeof(dit));
for(re i=1;i<=n;i++){
for(re j=i+1;j<=n;j++){
dit[j][i]=dit[i][j]=abs(abs(sca[i].x-sca[j].x)-abs(sca[i].y-sca[j].y));
q.push(node(i,j,dit[i][j]));
}
}
while(!q.empty()){
if(clock()-tim>800000)break;
int x=q.top().x,y=q.top().y,dis=q.top().dis;q.pop();
if(vis[x][y]||dit[x][y]!=dis)continue;
vis[x][y]=true;
for(re i=1;i<=n;i++){
if(i==x||i==y)continue;
if(vis[i][y])continue;
int tmp=abs(abs(sca[i].x-sca[x].x)-abs(sca[i].y-sca[x].y));
if(tmp+dis<dit[i][y]){
dit[y][i]=dit[i][y]=tmp+dis;
q.push(node(i,y,dit[i][y]));
}
}
for(re i=1;i<=n;i++){
if(i==x||i==y)continue;
if(vis[x][i])continue;
int tmp=abs(abs(sca[i].x-sca[y].x)-abs(sca[i].y-sca[y].y));
if(tmp+dis<dit[x][i]){
dit[x][i]=dit[i][x]=tmp+dis;
q.push(node(i,x,dit[x][i]));
}
}
}
ans=0x3f3f3f3f;
for(re i=1;i<=n;i++)
for(re j=i+1;j<=n;j++)
if(dit[i][j])ans=min(ans,dit[i][j]);
for(re i=1;i<=n;i++)
for(re j=i+1;j<=n;j++)
if(dit[i][j]==ans)sum++;
printf("%d\n%d",ans,sum);
}
其实正解是先转换坐标系,给它斜过来,然后就像题解说的做就好了,
并查集真的挺好用的,然后用vector维护距离为ans1的并查集就行了
转化坐标系是真的妙,自己手摸一下就有了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=1e5+5;
int n;
struct node{
int xp,yp,x,y,id;
node(){}
}sca[N];
struct BSU{
int fa[N],siz[N];
BSU(){for(re i=1;i<=100000;i++)fa[i]=i,siz[i]=1;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void merge(int x,int y){
if(!x||!y)return ;
int fx=find(x),fy=find(y);
if(fx==fy)return ;
fa[fx]=fy;siz[fy]+=siz[fx];
}
}bsu;
int mpx[N*4],mpy[N*4],bas=2e5+1,ans1=0x3f3f3f3f,ans2=0;
bool cmx(node a,node b){if(a.x!=b.x)return a.x<b.x;return a.y<b.y;}
bool cmy(node a,node b){if(a.y!=b.y)return a.y<b.y;return a.x<b.x;}
vector<pair<int,int> > vec[N*4];
signed main(){
scanf("%d",&n);
for(re i=1;i<=n;i++){
scanf("%d%d",&sca[i].xp,&sca[i].yp);
sca[i].x=sca[i].xp+sca[i].yp;
sca[i].y=sca[i].xp-sca[i].yp;
sca[i].id=i;
}
for(re i=1;i<=n;i++){
int xx=sca[i].x+bas,yy=sca[i].y+bas;
if(mpx[xx])bsu.merge(i,mpx[xx]);
else mpx[xx]=i;
if(mpy[yy])bsu.merge(i,mpy[yy]);
else mpy[yy]=i;
}
sort(sca+1,sca+n+1,cmx);
for(re i=1;i<n;i++){
int tmp=min(abs(sca[i].x-sca[i+1].x),abs(sca[i].y-sca[i+1].y));
int fx=bsu.find(sca[i].id),fy=bsu.find(sca[i+1].id);
vec[tmp].push_back(make_pair(min(fx,fy),max(fx,fy)));
if(tmp)ans1=min(ans1,tmp);
}
sort(sca+1,sca+n+1,cmy);
for(re i=1;i<n;i++){
int tmp=min(abs(sca[i].x-sca[i+1].x),abs(sca[i].y-sca[i+1].y));
int fx=bsu.find(sca[i].id),fy=bsu.find(sca[i+1].id);
vec[tmp].push_back(make_pair(min(fx,fy),max(fx,fy)));
if(tmp)ans1=min(ans1,tmp);
}
printf("%d\n",ans1);
sort(vec[ans1].begin(),vec[ans1].end());
vec[ans1].erase(unique(vec[ans1].begin(),vec[ans1].end()),vec[ans1].end());
//cout<<vec[ans1].size()<<endl;
for(re i=0;i<vec[ans1].size();i++){
if(vec[ans1][i].first==vec[ans1][i].second)continue;
//cout<<vec[ans1][i].first<<" "<<vec[ans1][i].second<<endl;
ans2+=bsu.siz[vec[ans1][i].first]*bsu.siz[vec[ans1][i].second];
}
printf("%d\n",ans2);
}
T3 零一串
这个我也没有改过,因为,我懒得动了
直接把每个1的移动的序列搞出来
然后就用队列维护就好了,维护这个序列中0的相对位置
沽~~~~
QQ:2953174821