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比较 ...
随机推荐
- hud 3308 LCIS 线段树 区间合并
题意: Q a b 查询[a, b]区间的最长连续递增子序列的长度 U a b 将下表为a的元素更新为b 区间合并一般都有3个数组:区间最值,左区间最值和右区间最值 具体详见代码 #include & ...
- 用阻塞队列实现一个生产者消费者模型?synchronized和lock有什么区别?
多线程当中的阻塞队列 主要实现类有 ArrayBlockingQueue是一个基于数组结构的有界阻塞队列,此队列按FIFO原则对元素进行排序 LinkedBlockingQueue是一个基于链表结构的 ...
- rabbitmq概念简介
AMQP协议 AMQP: Advanced Message Queue,高级队列协议. 特征: 这是一个在进程间传递异步消息的网络协议,因此数据的发送方.接收方以及容器(MQ)都可以在不同的设备上. ...
- php laravel5.5使用rabbitmq消息队列
1.安装rabbitmq 2.安装amqp扩展 3.在Laravel中配置 Rabbitmq 我是Laravel5.5,按照文档上说我只能用6版本 composer require vladimir- ...
- pdm文件name与comment互相同步
1.使用Powerdesigner工具将pdm文件的name同步至comment. 点击Tools->Execute Commands->Edit/Run Scripts 输入脚本: Op ...
- PHP利用百度ai实现文本和图片审核
之前做平台内容发布审核都是自己构建一套违禁词库,在代码中利用词库判断用户发布的内容,现在可以使用百度ai api完成这个功能.接下来就简单说下怎么做吧: 首先打开百度ai 开发平台 注册一个账号: 注 ...
- vuejs知识总结
1.Vue.js是当下很火的一个JavaScript MVVM库,它是以数据驱动和组件化的思想构建的.ViewModel是Vue.js的核心,它是一个Vue实例. <!DOCTYPE html& ...
- Python 操作 MySQL 的5种方式
不管你是做数据分析,还是网络爬虫,Web 开发.亦或是机器学习,你都离不开要和数据库打交道,而 MySQL 又是最流行的一种数据库,这篇文章介绍 Python 操作 MySQL 的5种方式,你可以在实 ...
- python 17篇 unittest单元测试框架
单元测试:开发程序的人自己测试自己的代码 unittest自动化测试框架 1.单元测试 import unittest def add(a,b): return a+b # 在运行时不要用run un ...
- C语言:#error命令,阻止程序编译
#error 指令用于在编译期间产生错误信息,并阻止程序的编译,其形式如下: #error error_message 例如,我们的程序针对 Linux 编写,不保证兼容 Windows,那么可以这样 ...