noip2017简要题解。
重新写了一下去年的题来看看自己到底是有多傻逼。
小凯的疑惑
- 打表。
时间复杂度
- 搞了一大坨题面,但是真正有用的信息只有几个:
- 判断他给你的复杂度是多少。
- 判断当前循环进不进的去。
- 判断当前循环产生的贡献。
- 判断当前的变量冲突和匹配。
- \(1\)傻逼,\(2,3\)就是分四种情况讨论一下就可以了,为了做\(2\)我们要开一个栈来记录之前所有的循环。
- 然后为了做\(2\)而开的栈,恰好就把\(4\)顺便做掉了。
- 所以代码巨短。
//100
#include<bits/stdc++.h>
#define R register int
using namespace std;
const int N=100001;
int t,n,Std,ans,now,ban,ERR;
int tp,Zm[N],Mark[N],ues[N],vis[30];
string S,Fir,Sec;char f,I;
void work(){
cin>>f;
if(f=='F'){
cin>>I;R II=I-'a';
if(vis[II])ERR=1;
vis[II]=1,cin>>Fir>>Sec,Zm[++tp]=II;
if(Fir=="n"&&Sec=="n"){
if(!ban)ans=max(ans,now);
Mark[tp]=0,ues[tp]=0;
}
else if(Fir=="n"&&Sec!="n")
ban++,Mark[tp]=1,ues[tp]=0;
else if(Fir!="n"&&Sec=="n"){
now++,Mark[tp]=0,ues[tp]=1;
if(!ban)ans=max(ans,now);
}
else {
R fir=0,sec=0;
for(R j=0,l=Fir.length();j<l;++j)fir=fir*10+Fir[j]-'0';
for(R j=0,l=Sec.length();j<l;++j)sec=sec*10+Sec[j]-'0';
if(fir<=sec){
if(!ban)ans=max(ans,now);
Mark[tp]=0,ues[tp]=0;
}
else ban++,Mark[tp]=1,ues[tp]=0;
}
}
else vis[Zm[tp]]=0,ban-=Mark[tp],now-=ues[tp],tp--;
}
void sol(){
cin>>n,Std=ans=ERR=tp=now=ban=0,cin>>S;
memset(vis,0,sizeof(vis));
if(S!="O(1)")
for(R j=4,l=S.length();j<l-1;++j)
Std=Std*10+S[j]-'0';
while(n--)work();ERR|=tp;
if(ERR)puts("ERR");
else if(ans==Std)puts("Yes");
else puts("No");
}
int main(){
cin>>t;while(t--)sol();
return 0;
}
逛公园
- \(K\leq 50\),就是让你\(dp\)的。
- 设\(f_{i,j}\)表示当前在\(i\)点,额外走过的路恰好为\(j\)的方案数。
- 这个正反\(dij\)之后就很好转移了。
- 如果不存在\(0\)环,那么转移就一定满足拓扑关系(最短路性质)。
- 但是存在\(0\)环就不满足拓扑关系了。
- 所以利用这一点来判断\(0\)环即可,如果当前\(dp\)状态已经存在于\(dfs\)栈中,则不合法。
- 至于为什么\(dp\)到的\(0\)环一定走的到?
- 因为\(dp\)的状态一定是和终点状态相通的。
//100
#include<bits/stdc++.h>
#define R register int
#define ll long long
using namespace std;
const int N=100001;
const int M=400001;
int t,n,m,K,mod,u,v,x,ans;
int vis[N][51],f[N][51];
struct ip{int vl,id;};
int operator < (ip x,ip y){return x.vl>y.vl;}
priority_queue<ip>Q;
void add(R &x,R y){x=(x+y>=mod?x+y-mod:x+y);}
int gi(){
R x=0,k=1;char c=getchar();
while((c<'0'||c>'9')&&c!='-')c=getchar();
if(c=='-')k=-1,c=getchar();
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*k;
}
struct Gra{
int cnt,hd[N],to[M],w[M],nt[M];
int Dis[N],vis[N];
void link(R f,R t,R d){nt[++cnt]=hd[f],to[cnt]=t,w[cnt]=d,hd[f]=cnt;}
void init(){
memset(hd,0,sizeof(hd)),cnt=ans=0;
memset(vis,0,sizeof(vis));
memset(Dis,0x7f,sizeof(Dis));
}
void dij(R s){
Dis[s]=0,Q.push((ip){0,s});
while(!Q.empty()){
R i=Q.top().id;Q.pop();
if(vis[i])continue;vis[i]=1;
for(R k=hd[i];k;k=nt[k])
if(Dis[to[k]]>Dis[i]+w[k]){
Dis[to[k]]=Dis[i]+w[k];
Q.push((ip){Dis[to[k]],to[k]});
}
}
}
}Z,F;
int Dfs(R i,R j){
if(vis[i][j])return -1;
if(f[i][j]!=-1)return f[i][j];
f[i][j]=(i==1&&j==0),vis[i][j]=1;
for(R k=F.hd[i];k;k=F.nt[k]){
R v=F.to[k],p=j-(F.Dis[i]+F.w[k]-F.Dis[v]);
if(p>=0){
R g=Dfs(v,p);
if(g==-1)return -1;
add(f[i][j],g);
}
}
vis[i][j]=0;return f[i][j];
}
void sol(){
Z.init(),F.init();
n=gi(),m=gi(),K=gi(),mod=gi();
for(R i=1;i<=m;++i){
u=gi(),v=gi(),x=gi();
Z.link(u,v,x),F.link(v,u,x);
}
Z.dij(1),F.dij(n);
memset(f,-1,sizeof(f));
memset(vis,0,sizeof(vis));
for(R i=0;i<=K;++i){
f[n][i]=Dfs(n,i);
if(f[n][i]==-1){puts("-1");return ;}
else add(ans,f[n][i]);
}
printf("%d\n",ans);
}
int main(){
t=gi();while(t--)sol();
return 0;
}
奶酪
- 连通性,并查集。
- 暴力连边即可。
- 防止爆\(longlong\)的方法,判断这个$$x2+y2\leq4*r2-z2$$
- 就可以了,效果很好。
//100
#include<bits/stdc++.h>
#define R register int
#define ll long long
using namespace std;
const int N=5101;
int t,n,fa[N];ll h,r;
struct Qs{ll x,y,z;}Q[N];
int gi(){
R x=0,k=1;char c=getchar();
while((c<'0'||c>'9')&&c!='-')c=getchar();
if(c=='-')k=-1,c=getchar();
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*k;
}
int find(R x){if(fa[x]!=x)fa[x]=find(fa[x]);return fa[x];}
ll sqr(ll x){return x*x;}
int Dis(R i,R j){
return (sqr(Q[i].x-Q[j].x)+sqr(Q[i].y-Q[j].y)<=4ll*sqr(r)-sqr(Q[i].z-Q[j].z));
}
void sol(){
n=gi(),h=gi(),r=gi();
for(R i=1;i<=n;++i)
Q[i].x=gi(),Q[i].y=gi(),Q[i].z=gi(),fa[i]=i;
for(R i=1;i<=n;++i)
for(R j=i+1;j<=n;++j)
if(Dis(i,j)){
R fu=find(i),fv=find(j);
fa[fu]=fv;
}
fa[n+1]=n+1,fa[n+2]=n+2;
for(R i=1;i<=n;++i)
if(Q[i].z+r>=h){
R fu=find(i),fv=find(n+1);
fa[fu]=fv;
}
for(R i=1;i<=n;++i)
if(Q[i].z-r<=0){
R fu=find(i),fv=find(n+2);
fa[fu]=fv;
}
puts(find(n+1)==find(n+2)?"Yes":"No");
}
int main(){
t=gi();while(t--)sol();
return 0;
}
宝藏
- 以前落实这个题目的时候打了个假算法。
- 网上的\(dp\)大多都不正确,正解是子集\(dp\)。
- 先暴搜,然后套个\(A*\),发现跑得比较快。
- 然后\(hash\)当前集合状态和到根节点距离,存下来。
- 然后就可以\(1000ms\)内通过所有测试点。
- 可以过网上我看到的所有\(hack\)数据。
//100
#include<bits/stdc++.h>
#define ull unsigned long long
#define R register int
using namespace std;
const int N=600005;
const int M=13;
const int bas=257;
int n,m,Mp[M][M];
int ans,Dis[N];
map<ull,int>G;
int gi(){
R x=0,k=1;char c=getchar();
while((c<'0'||c>'9')&&c!='-')c=getchar();
if(c=='-')k=-1,c=getchar();
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*k;
}
int check(R S){
R res=0;
for(R j=1;j<=n;++j)
if(((1<<(j-1))&S)==0){
R Mn=1e9;
for(R k=1;k<=n;++k)
Mn=min(Mn,Mp[j][k]);
res+=Mn;
}
return res;
}
ull Hash(R S){
ull res1=0,res2=0;
for(R j=1;j<=n;++j)
res1=res1*bas+j,res2=res2*bas+Dis[j];
return res1^res2;
}
void Dfs(R S,R now){
if(S==(1<<n)-1){ans=min(now,ans);return;}
if(check(S)>=ans-now)return ;
ull has=Hash(S);
if(G.find(has)!=G.end())
if(G[has]<=now)return ;
G[has]=now;
for(R k=1;k<=n;++k)
if(((1<<(k-1))&S)==0){
R T=((1<<(k-1))|S);
for(R j=1;j<=n;++j)
if(((1<<(j-1))&S)&&Mp[j][k]!=Mp[0][0]){
Dis[k]=Dis[j]+1;
Dfs(T,now+Dis[j]*Mp[j][k]);
Dis[k]=0;
}
}
}
int main(){
freopen("testdata(2).in","r",stdin);
n=gi(),m=gi(),ans=2e9;
memset(Mp,0x7f,sizeof(Mp));
for(R i=1;i<=m;++i){
R u=gi(),v=gi(),x=gi();
Mp[u][v]=min(Mp[u][v],x);
Mp[v][u]=Mp[u][v];
}
for(R i=1;i<=n;++i){
memset(Dis,0,sizeof(Dis));
Dis[i]=1,Dfs(1<<(i-1),0);
}
cout<<ans<<endl;
return 0;
}
列队
- 这个真的是套路题,数据结构做多了就没什么意思了。
- \(O(q^2)\)的做法是每次考虑之前的询问对当前询问的影响。
- 比如说你这次询问\((i,j)\)是谁,上一次询问的是\((i,j−1)\)
- 那么你就知道了这一次在\((i,j)\)的人实际上就是上一次在\((i,j+1)\)的人。
- 这样依次推到最开始就可以了。
- \(80\)分只有一条链,在上面线段树二分即可。
- \(100\)分就是开很多个线段树。
- 网上\(100\)分代码一大堆,这里给出\(70\)分部分分代码。
//70
#include<bits/stdc++.h>
#define R register int
#define ll long long
using namespace std;
const int N=600005;
int n,m,q;
int gi(){
R x=0,k=1;char c=getchar();
while((c<'0'||c>'9')&&c!='-')c=getchar();
if(c=='-')k=-1,c=getchar();
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*k;
}
namespace cpp1{
const int N=601;
struct Qs{int x,y;}Q[N];
ll Idx(R x,R y){return 1ll*(x-1)*m+y;}
void Main(){
for(R i=1;i<=q;++i)Q[i].x=gi(),Q[i].y=gi();
for(R i=1;i<=q;++i){
R x=Q[i].x,y=Q[i].y;
for(R j=i-1;j>=1;--j){
if(Q[j].x==x&&Q[j].y<=y&&y<m)y++;
else if(y==m&&Q[j].x<=x&&x<n)x++;
else if(x==n&&y==m)x=Q[j].x,y=Q[j].y;
}
printf("%lld\n",Idx(x,y));
}
exit(0);
}
}
#define low(x) (x&(-x))
namespace cpp2{
int len,vl[N*4];
vector<int>G;
int query(R le,R ri,R lim,R i){
if(le==ri)return le;
R mid=(le+ri)>>1,ls=(i<<1),rs=(ls|1),F=mid-le+1-vl[ls];
if(F<lim)return query(mid+1,ri,lim-F,rs);
else return query(le,mid,lim,ls);
}
void mdf(R le,R ri,R pos,R i){
if(le==ri){vl[i]++;return ;}
R mid=(le+ri)>>1,ls=(i<<1),rs=(ls|1);
if(pos<=mid)mdf(le,mid,pos,ls);else mdf(mid+1,ri,pos,rs);
vl[i]=vl[ls]+vl[rs];
}
void Main(){
len=m+q;
for(R i=1;i<=q;++i){
gi();R x=gi();
R ans=query(1,len,x,1);
if(ans<=m)printf("%d\n",ans),G.push_back(ans);
else printf("%d\n",G[ans-m-1]),G.push_back(G[ans-m-1]);
mdf(1,len,ans,1);
}
}
}
int main(){
n=gi(),m=gi(),q=gi();
if(q<=500)cpp1::Main();
if(n==1)cpp2::Main();
return 0;
}
noip2017简要题解。的更多相关文章
- 【题解】NOIP2017 提高组 简要题解
[题解]NOIP2017 提高组 简要题解 小凯的疑惑(数论) 不讲 时间复杂度 大力模拟 奶酪 并查集模板题 宝藏 最优解一定存在一种构造方法是按照深度一步步生成所有的联通性. 枚举一个根,随后设\ ...
- Noip 2014酱油记+简要题解
好吧,day2T1把d默认为1也是醉了,现在只能期待数据弱然后怒卡一等线吧QAQ Day0 第一次下午出发啊真是不错,才2小时左右就到了233,在车上把sao和fate补掉就到了= = 然后到宾馆之后 ...
- Tsinghua 2018 DSA PA2简要题解
反正没时间写,先把简要题解(嘴巴A题)都给他写了记录一下. upd:任务倒是完成了,我也自闭了. CST2018 2-1 Meteorites: 乘法版的石子合并,堆 + 高精度. 写起来有点烦貌似. ...
- Codeforces 863 简要题解
文章目录 A题 B题 C题 D题 E题 F题 G题 传送门 简要题解?因为最后一题太毒不想写了所以其实是部分题解... A题 传送门 题意简述:给你一个数,问你能不能通过加前导000使其成为一个回文数 ...
- HNOI2018简要题解
HNOI2018简要题解 D1T1 寻宝游戏 题意 某大学每年都会有一次 Mystery Hunt 的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会. 作为 ...
- JXOI2018简要题解
JXOI2018简要题解 T1 排序问题 题意 九条可怜是一个热爱思考的女孩子. 九条可怜最近正在研究各种排序的性质,她发现了一种很有趣的排序方法: Gobo sort ! Gobo sort 的算法 ...
- BJOI2018简要题解
BJOI2018简要题解 D1T1 二进制 题意 pupil 发现对于一个十进制数,无论怎么将其的数字重新排列,均不影响其是不是 \(3\) 的倍数.他想研究对于二进制,是否也有类似的性质. 于是他生 ...
- CQOI2018简要题解
CQOI2018简要题解 D1T1 破解 D-H 协议 题意 Diffie-Hellman 密钥交换协议是一种简单有效的密钥交换方法.它可以让通讯双方在没有事先约定密钥(密码)的情况下,通过不安全的信 ...
- AtCoder ExaWizards 2019 简要题解
AtCoder ExaWizards 2019 简要题解 Tags:题解 link:https://atcoder.jp/contests/exawizards2019 很水的一场ARC啊,随随便便就 ...
随机推荐
- JRE、JDK、JVM 及 JIT 之间有什么不同
java虚拟机(JVM) 使用java编程语言的主要优势就是平台的独立性.你曾经想知道过java怎么实现平台的独立性吗?对,就是虚拟机,它抽象化了硬件设备,开发者和他们的程序的得以操作系统.虚 ...
- 三、Jmeter生成HTML报告
1.执行jmeter -n -t [接口脚本地址] -l [test.jtl地址] -e -o [报告输出地址] 例如:jmeter -n -t C:\chushujin\youxinscript\j ...
- python - property 属性函数
Python中有一个被称为属性函数(property)的小概念,它可以做一些有用的事情.在这篇文章中,我们将看到如何能做以下几点: 将类方法转换为只读属性 重新实现一个属性的setter和getter ...
- Spring 之 IOC ,DI 理论
本文是依照极客学院java<Spring之IOC>章节学习的心得.随笔记录 浅谈IOC:(Inversion of Control, 控制反转) Spring 核心容器,贯穿始终.所谓IO ...
- pycharm基础使用方法
0.前言 Pycharm 作为一款针对 Python 的编辑器,配置简单.功能强大.使用起来省时省心,对初学者友好,这也是为什么编程教室一直推荐新手使用 Pycharm 的原因.本文我们将介绍 py ...
- 中国MOOC_零基础学Java语言_第5周 数组
第5周 数组 5.1 数组 5.2 数组计算 public class Main { public static void main(String[] args) { for (int i = 1; ...
- 【Java安全】关于Java中常用加密/解密方法的实现
安全问题已经成为一个越来越重要的问题,在Java中如何对重要数据进行加密解密是本文的主要内容. 一.常用的加密/解密算法 1.Base64 严格来说Base64并不是一种加密/解密算法,而是一种编码方 ...
- ARTS挑战
最近有点迷茫,感觉自己工作了一年多,技术成长有限,我要做出改变.2019年11月2日,就从今天开始,参加耗子叔的ARTS挑战. ARTS的初衷 Algorithm:主要是为了编程训练和学习.每周至少做 ...
- 【ABAP系列】SAP ABAP 刷新SCREEN的方法
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP 刷新SCREE ...
- Scratch少儿编程系列:(一)版本的选择及安装
工欲善其事必先利其器,为了使用Scratch,首先要到官网上下载相关软件. 官网链接地址为:https://scratch.mit.edu/download,我用的是Windows系统,下载对应的安装 ...