812考试总结(NOIP模拟37)[数列·数对·最小距离·真相]
前言
考得挺憋屈的。。。
先是搞了两个半小时的 T1 后来发现假了,又没多想跳了。。
然后一看 T2 这不是队长快跑嘛。。。
先是根据自己的想法打了一遍(考完之后发现是对的。。)
然后回想了一下之前的题,不对呀,我记得有一个 if-else 的。
接下来我就这么改了,然后连样例都过不去了。。。
后来 40min 码完了两个暴力(还有一个打错了。。)
最后剩下了 30min 又去看 T1 了,推出来了半个正解 50pts
感觉哪个都有一点感觉,会但不是完全会。。
T1 数列
解题思路
扩展欧几里德。。。
发现当 x 为 1 的时候可以直接用扩展欧几里德求出来。
也可以进而求出其他数的一组可行但不一定是最优的解。
假设已经有 \(ax'+by'=m\)
可以推出: \(ax'+kab+by'-kab=m\)
因此可以得出解集: \((x'+kb,y'-ka)\)
然后取最小的正值或者最大的负值就好了。
注意这里最优的 x 不一定对应最优的 y 。
code
50pts
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=1e5+10;
int n,a,b,g,lcm,ans,s[N],w[N];
struct Node
{
int x,y;
};
int gcd(int x,int y)
{
if(!y) return x;
return gcd(y,x%y);
}
Node exgcd(int a,int b)
{
if(!b) return (Node){1,0};
Node temp=exgcd(b,a%b);
int x=temp.x,y=temp.y;
return (Node){y,x-a/b*y};
}
signed main()
{
n=read(); a=read(); b=read();
g=gcd(a,b);
Node t=exgcd(a,b);
t.x=abs(t.x); t.y=abs(t.y);
for(int i=1;i<=n;i++)
{
s[i]=read();
if(s[i]<0) s[i]=-s[i];
if(s[i]%g){printf("-1");return 0;}
}
for(int i=1;i<=n;i++)
s[i]/=g;
a/=g; b/=g; lcm=a*b/g;
for(int i=1;i<=n;i++)
{
int tmp1,tmp2,x,y;
x=(s[i]*t.x/b)*b;
y=(s[i]*t.y/a)*a;
tmp1=min(abs(b+x-s[i]*t.x),abs(s[i]*t.x-x));
tmp2=min(abs(a+y-s[i]*t.y),abs(s[i]*t.y-y));
ans+=tmp1+tmp2;
}
printf("%lld",ans);
return 0;
}
正解
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=1e5+10,INF=1e18;
int n,a,b,g,lcm,ans,s[N],w[N];
struct Node
{
int x,y;
};
int gcd(int x,int y)
{
if(!y) return x;
return gcd(y,x%y);
}
Node exgcd(int a,int b)
{
if(!b) return (Node){1,0};
Node temp=exgcd(b,a%b);
int x=temp.x,y=temp.y;
return (Node){y,x-a/b*y};
}
signed main()
{
n=read(); a=abs(read()); b=abs(read());
if(a>b) swap(a,b);
g=gcd(a,b);
Node t=exgcd(a,b);
for(int i=1;i<=n;i++)
{
s[i]=read();
if(s[i]<0) s[i]=-s[i];
if(s[i]%g){printf("-1");return 0;}
}
a/=g; b/=g;
for(int i=1;i<=n;i++) s[i]/=g;
for(int i=1;i<=n;i++)
{
int num=s[i]/b; s[i]%=b;
int x=s[i]*t.x;
int y=s[i]*t.y+num;
int temp=abs(x)+abs(y);
if(x>0)
{
int tmp=abs(x)/b;
x-=tmp*b; y+=tmp*a;
temp=min(temp,abs(x)+abs(y));
temp=min(temp,abs(x-b)+abs(y+a));
}
else
{
int tmp=abs(x)/b;
x+=tmp*b; y-=tmp*a;
temp=min(temp,abs(x)+abs(y));
temp=min(temp,abs(x+b)+abs(y-a));
}
ans+=temp;
}
printf("%lld",ans);
return 0;
}
T2 数对
解题思路
首先证明一下按照 \(a+b\) 从大到小排序的正确性。
假设 i 位于 j 之前,那么一定是 \(a_i<b_j\) 并且 \(b_i>a_j\) 更优。
所以此时的 \(a_i+b_i<a_j+b_j\)(严格来讲应该有等于的情况)
然后对于相反的情况也是差不多,剩下两种情况的排序的顺序无所谓。。
接下来就是对于 \([1,min(a_i,b_i)]\) 以及 \([a_i+1,b_i]\) 这两个区间的更新了。
设 DP数组 \(f_{i,j}\) 表示排序之后的序列选前 i 个数,最大的 a 为 j 的最大值。。
发现这个可以线段树优化,单点修改,区间修改,区间查询就好了。
- 注意:排序要在离散化之前,单点修改要取 max。
code
60pts
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=1e5+10,M=3e3+10;
int n,ans,f[M][M<<1];
int cnt,lsh[N];
struct Node
{
int a,b,w;
}s[N];
bool comp(Node x,Node y)
{
return x.a+x.b<y.a+y.b;
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)
{
s[i].a=read(); s[i].b=read(); s[i].w=read();
lsh[++cnt]=s[i].a; lsh[++cnt]=s[i].b;
}
sort(s+1,s+n+1,comp);
sort(lsh+1,lsh+cnt+1);
cnt=unique(lsh+1,lsh+cnt+1)-lsh-1;
for(int i=1;i<=n;i++)
{
s[i].a=lower_bound(lsh+1,lsh+cnt+1,s[i].a)-lsh;
s[i].b=lower_bound(lsh+1,lsh+cnt+1,s[i].b)-lsh;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=cnt;j++)
f[i][j]=f[i-1][j];
for(int j=1;j<=min(s[i].a,s[i].b);j++)
f[i][s[i].a]=max(f[i][s[i].a],f[i-1][j]+s[i].w);
for(int j=s[i].a+1;j<=s[i].b;j++)
f[i][j]=max(f[i][j],f[i-1][j]+s[i].w);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=cnt;j++)
ans=max(ans,f[i][j]);
printf("%lld",ans);
return 0;
}
正解
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
#define ls x<<1
#define rs x<<1|1
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=2e5+10;
int n,ans,tre[N<<2],laz[N<<2];
int cnt,lsh[N];
struct Node
{
int a,b,w;
}s[N];
bool comp(Node x,Node y)
{
return x.a+x.b<y.a+y.b;
}
void push_up(int x)
{
tre[x]=max(tre[ls],tre[rs]);
}
void push_down(int x)
{
if(!laz[x]) return ;
tre[ls]+=laz[x];
tre[rs]+=laz[x];
laz[ls]+=laz[x];
laz[rs]+=laz[x];
laz[x]=0;
}
int query(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R) return tre[x];
push_down(x);
int mid=(l+r)>>1,ans1=0,ans2=0;
if(L<=mid) ans1=query(ls,l,mid,L,R);
if(R>mid) ans2=query(rs,mid+1,r,L,R);
push_up(x);
return max(ans1,ans2);
}
void update(int x,int l,int r,int L,int R,int num)
{
if(L<=l&&r<=R)
{
tre[x]+=num;
laz[x]+=num;
return ;
}
push_down(x);
int mid=(l+r)>>1;
if(L<=mid) update(ls,l,mid,L,R,num);
if(R>mid) update(rs,mid+1,r,L,R,num);
push_up(x);
}
void insert(int x,int l,int r,int pos,int num)
{
if(l==r)
{
tre[x]=max(tre[x],num);
return ;
}
push_down(x);
int mid=(l+r)>>1;
if(pos<=mid) insert(ls,l,mid,pos,num);
else insert(rs,mid+1,r,pos,num);
push_up(x);
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)
{
s[i].a=read(); s[i].b=read(); s[i].w=read();
lsh[++cnt]=s[i].a; lsh[++cnt]=s[i].b;
}
sort(s+1,s+n+1,comp);
sort(lsh+1,lsh+cnt+1);
cnt=unique(lsh+1,lsh+cnt+1)-lsh-1;
for(int i=1;i<=n;i++)
{
s[i].a=lower_bound(lsh+1,lsh+cnt+1,s[i].a)-lsh;
s[i].b=lower_bound(lsh+1,lsh+cnt+1,s[i].b)-lsh;
}
for(int i=1;i<=n;i++)
{
if(s[i].b>s[i].a) update(1,1,cnt,s[i].a+1,s[i].b,s[i].w);
insert(1,1,cnt,s[i].a,query(1,1,cnt,1,min(s[i].a,s[i].b))+s[i].w);
}
printf("%lld",tre[1]);
return 0;
}
T3 最小距离
解题思路
思路极简。。
多源最短路,同时记录每一个点的最小值来自于哪一个特殊点,跑一下 Dij
接下来枚举枚举每一条边,用这条边的两个端点的两距离个最小值与边权之和更新两个特殊点的答案就好了。
然后就没有然后了。。
code
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=2e5+10;
int n,m,p,s[N],dis[N],ans[N],pre[N];
bool vis[N];
int tot=1,head[N],nxt[N<<1],ver[N<<1],edge[N<<1];
struct Road
{
int l,r,val;
}pat[N];
priority_queue<pair<int,int> > q;
void add(int x,int y,int val)
{
ver[++tot]=y;
edge[tot]=val;
nxt[tot]=head[x];
head[x]=tot;
}
void Dij()
{
memset(dis,0x3f,sizeof(dis));
for(int i=1;i<=p;i++)
{
pre[s[i]]=s[i];
dis[s[i]]=0;
q.push(make_pair(0,s[i]));
}
while(!q.empty())
{
int x=q.top().second; q.pop();
if(vis[x]) continue;
vis[x]=true;
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i];
if(dis[x]+edge[i]<dis[to])
{
pre[to]=pre[x];
dis[to]=dis[x]+edge[i];
q.push(make_pair(-dis[to],to));
}
}
}
}
signed main()
{
n=read(); m=read(); p=read();
for(int i=1;i<=p;i++) s[i]=read();
memset(ans,0x3f,sizeof(ans));
for(int i=1,x,y,val;i<=m;i++)
{
pat[i].l=x=read();
pat[i].r=y=read();
pat[i].val=val=read();
add(x,y,val);
add(y,x,val);
}
Dij();
for(int i=1;i<=m;i++)
{
int x=pat[i].l,y=pat[i].r;
if(pre[x]==pre[y]) continue;
ans[pre[x]]=min(ans[pre[x]],dis[x]+dis[y]+pat[i].val);
ans[pre[y]]=min(ans[pre[y]],dis[x]+dis[y]+pat[i].val);
}
for(int i=1;i<=p;i++)
printf("%lld ",ans[s[i]]);
return 0;
}
T4 真相
解题思路
思路来自 AaMuXiiiiii 。。
记录每一个 \(\$\) 的位置以及所代表的值。
分别枚举所有的值,然后逆推回去看真话的数量是否一直。
如果都不成立的话,在判断一下说的都是假话的话是否可行。
如果没有 \(\$\) 的话直接分类讨论第一个是否是真话是否合法就好了。
代码实现细节较多,数组清零不可以 memset 会 TLE
code
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=1e5+10;
int T,n,s[N],t[N],pre[N][2],ans[N][2];
map<int,bool> b;
vector<int> pos,v;
string opt;
void clear()
{
b.clear();
for(int i=0;i<=n;i++) pre[i][0]=pre[i][1]=ans[i][0]=ans[i][1]=0;
vector<int>().swap(pos); vector<int>().swap(v);
}
void solve()
{
n=read(); int flag=0,maxn=0;
for(int i=1;i<=n;i++)
{
cin>>opt;
if(opt[0]=='$') scanf("%lld",&s[i]),flag=i;
if(opt[0]=='+') s[i]=-1;
if(opt[0]=='-') s[i]=-2;
maxn=max(maxn,s[i]);
}
for(int i=1;i<=n-flag;i++) t[i]=s[i+flag];
for(int i=1;i<=flag;i++) t[i+n-flag]=s[i];
memcpy(s,t,sizeof(t));
if(flag)
{
for(int i=1;i<=n;i++)
if(s[i]>=0)
{
pos.push_back(i);
if(!b[s[i]]){b[s[i]]=true;v.push_back(s[i]);}
}
for(int i=n;i>=1;i--)
{
if(s[i]<0) continue;
int las=true;
pre[i][1]=1;
for(int j=i-1;j>=1;j--)
{
if(s[j]>=0) break;
if(s[j]==-1)
{
if(las) pre[i][1]++,las=true;
else las=false;
}
else
{
if(!las) pre[i][1]++,las=true;
else las=false;
}
}
las=false;
for(int j=i-1;j>=1;j--)
{
if(s[j]>=0) break;
if(s[j]==-1)
{
if(las) pre[i][0]++,las=true;
else las=false;
}
else
{
if(!las) pre[i][0]++,las=true;
else las=false;
}
}
}
int all=0;
for(int i=0;i<pos.size();i++)
{
ans[s[pos[i]]][0]+=pre[pos[i]][0];
ans[s[pos[i]]][1]+=pre[pos[i]][1];
}
for(int i=0;i<v.size();i++)
all+=ans[v[i]][0];
for(int i=0;i<v.size();i++)
if(ans[v[i]][1]-ans[v[i]][0]+all==v[i])
{
printf("consistent\n");
clear();
return ;
}
int sum=0;
for(int i=0;i<pos.size();i++)
sum+=pre[pos[i]][0];
for(int i=0;i<v.size();i++)
if(sum==v[i])
{
printf("inconsistent\n");
clear();
return ;
}
printf("consistent\n");
clear();
return ;
}
bool las=true;
for(int i=n-1;i>=1;i--)
if(s[i]==-2)
las^=1;
if(las&&s[n]==-1)
{
printf("consistent\n");
return ;
}
if(!las&&s[n]==-2)
{
printf("consistent\n");
return ;
}
las=false;
for(int i=n-1;i>=1;i--)
if(s[i]==-2)
las^=1;
if(las&&s[n]==-2)
{
printf("consistent\n");
return ;
}
if(!las&&s[n]==-1)
{
printf("consistent\n");
return ;
}
printf("inconsistent\n");
}
signed main()
{
T=read();
while(T--) solve();
return 0;
}
812考试总结(NOIP模拟37)[数列·数对·最小距离·真相]的更多相关文章
- 2021.8.12考试总结[NOIP模拟37]
T1 数列 考场上切掉的简单题. $a$,$b$与数列中数的正负值对答案无关.全当作正数计算即可. $exgcd$解未知数系数为$a$,$b$,加和为$gcd(a,b)$的不定方程组,再枚举每个数.如 ...
- 6.17考试总结(NOIP模拟8)[星际旅行·砍树·超级树·求和]
6.17考试总结(NOIP模拟8) 背景 考得不咋样,有一个非常遗憾的地方:最后一题少取膜了,\(100pts->40pts\),改了这么多年的错还是头一回看见以下的情景... T1星际旅行 前 ...
- 5.23考试总结(NOIP模拟2)
5.23考试总结(NOIP模拟2) 洛谷题单 看第一题第一眼,不好打呀;看第一题样例又一眼,诶,我直接一手小阶乘走人 然后就急忙去干T2T3了 后来考完一看,只有\(T1\)骗到了\(15pts\)[ ...
- 5.22考试总结(NOIP模拟1)
5.22考试总结(NOIP模拟1) 改题记录 T1 序列 题解 暴力思路很好想,分数也很好想\(QAQ\) (反正我只拿了5pts) 正解的话: 先用欧拉筛把1-n的素数筛出来 void get_Pr ...
- 2021.9.17考试总结[NOIP模拟55]
有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...
- [考试总结]noip模拟23
因为考试过多,所以学校的博客就暂时咕掉了,放到家里来写 不过话说,vscode的markdown编辑器还是真的很好用 先把 \(noip\) 模拟 \(23\) 的总结写了吧.. 俗话说:" ...
- 8.23考试总结(NOIP模拟46)[数数·数树·鼠树·ckw的树]
T1 数数 解题思路 大概是一个签到题的感觉...(但是 pyt 并没有签上) 第一题当然可以找规律,但是咱们还是老老实实搞正解吧... 先从小到大拍个序,这样可以保证 \(a_l<a_r\) ...
- 「考试」noip模拟9,11,13
9.1 辣鸡 可以把答案分成 每个矩形内部连线 和 矩形之间的连线 两部分 前半部分即为\(2(w-1)(h-1)\),后半部分可以模拟求(就是讨论四种相邻的情况) 如果\(n^2\)选择暴力模拟是有 ...
- 6.11考试总结(NOIP模拟7)
背景 时间分配与得分成反比,T1 20min 73pts,T2 1h 30pts,T3 2h 15pts(没有更新tot值,本来应该是40pts的,算是本次考试中最遗憾的地方了吧),改起来就是T3比较 ...
随机推荐
- 配置本地yum源以及挂载镜像
配置本地yum源以及挂载镜像(centos7.6) 配置yum源 # cd /etc/yum.repos.d 可以备份或者删除里面的文件 新建文件 # touch /etc/yum.repos.d/l ...
- C++中运算符的重载
运算符重载相当于运算符的函数重载,用于对已有的运算符进行重新定义,赋予其另一种功能,以适应不同的数据类型.我们之前提到过C++中的函数重载,可以根据形参的不同调用不同的函数,那么运算符重载跟函数重载的 ...
- SuperEdge 云边隧道新特性:从云端SSH运维边缘节点
背景 在边缘集群的场景下边缘节点分布在不同的区域,且边缘节点和云端之间是单向网络,边缘节点可以访问云端节点,云端节点无法直接访问边缘节点,给边缘节点的运维带来很大不便,如果可以从云端SSH登录到边缘节 ...
- 45、screen命令
1.screen命令介绍: 当我们在使用linux远程工具进行远程访问服务器时,进行远程访问的界面往往不能关掉,否则程序将不再运行.而且,程序 在运行的过程中,还必须时刻保证网络的通常,这些条件都很难 ...
- 使用命令行操作MySQL 及 语法
在使用之前先要确保服务中的MySQL 已启动,否则会报错:ERROR 2003 (HY000): Can't connect to MySQL server on 'localhost' (10061 ...
- JavaWeb中Servlet和Jsp跳转路径的写法
最近学习时,常常要写一些页面之间的跳转或者前台和后端之间的跳转 下面总结一下自己对于这些跳转路径的写法 声明:以下讲到的jsp文件都默认在WebRoot目录下 1.表单(Jsp)->Servle ...
- XCTF getit
一.查壳 是linux的文件.没加壳 二.拖入ida 分析一下逻辑,发现就是t的值就是flag. 写个exp就出来了. 三.exp分享 s='c61b68366edeb7bdce3c6820314b7 ...
- buu 红帽杯easyre
一.拖入ida静态分析 找到关键函数,然后 这步是可以得出前4个字符是flag,不知道为啥我这边的v15的内存地址为空,不然可以异或解出来的,ida日常抽风... 十次的base64加密,我用在线平台 ...
- ARTS第八周
1.Algorithm:每周至少做一个 leetcode 的算法题2.Review:阅读并点评至少一篇英文技术文章3.Tip:学习至少一个技术技巧4.Share:分享一篇有观点和思考的技术文章 以下是 ...
- 永恒之蓝ms17_010漏洞复现
1.什么是永恒之蓝 永恒之蓝(Eternal Blue)爆发于2017年4月14日晚,是一种利用Windows系统的SMB协议漏洞来获取系统的最高权限,以此来控制被入侵的计算机. 2.SMB协议 SM ...