为何我对T3情有独钟

T1

不难发现,题目要求的就是 \(ax+by=c\) ,已知 \(a,b,c\) ,求 \(\min\{|a|+|b|\}\) ,那就用扩欧求一组特解,再分情况讨论即可。

Code
#include<cstdio>
#define MAX 100010
#define re register
#define int long long
namespace OMA
{
struct stream
{
template<typename type>inline stream &operator >>(type &s)
{
int w=1; s=0; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
return s*=w,*this;
}
}cin;
inline int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{ x = 1,y = 0; return a; }
int d = exgcd(b,a%b,x,y);
int z = x; x = y; y = z-y*(a/b);
return d;
}
inline int min(int a,int b)
{ return a<b?a:b; }
inline int abs(int a)
{ return a>=0?a:-a; }
int n,a,b,x[MAX],ans;
signed main()
{
cin >> n >> a >> b;
if(a>b)
{ int t=a; a=b; b=t; }
int xi,yi;
int gcd = exgcd(a,b,xi,yi);
a /= gcd,b/= gcd;
for(re int i=1; i<=n; i++)
{
cin >> x[i];
if(x[i]%gcd)
{ printf("-1\n"); return 0; }
}
for(re int i=1,x1,y1,k; i<=n; i++)
{
x1 = xi*x[i]/gcd,y1 = yi*x[i]/gcd,k = abs(x1/b);
if(x1>=0&&y1<=0)
{ ans += min(abs(x1-k*b)+abs(y1+k*a),abs(x1-(k+1)*b)+abs(y1+(k+1)*a)); }
else if(x1<=0&&y1>=0)
{ ans += min(abs(x1+k*b)+abs(y1-k*a),abs(x1+(k+1)*b)+abs(y1-(k+1)*a)); }
}
printf("%lld\n",ans);
return 0;
}
}
signed main()
{ return OMA::main(); }

T2

考场上一眼看上去像队长快跑,然而带权。

但其实如果那道题真的明白了,这道也不算难。

然而我...

首先写出基础dp,设 \(dp_{i,j}\) 表示当前选到了第 \(i\) 个数对,其中,所选的数对中最大的 \(a\) 为 \(j\),则可以列出转移方程:

  1. 选 \(i\) 后,最大值不是 \(a_{i}\) ,则,
\[dp_{i,j} = \max\{dp_{i-1,j}\}+w_{i}\;,j\in[a_{i},b_{i}]
\]
  1. 选 \(i\) 后,最大值为 \(a_{i}\) ,则,
\[dp_{i,a_{i}} = \max\{dp_{i-1,j}\}+w_{i}\;,j\in[1,\min(a_{i},b_{i})]
\]
  1. 不选,直接由上层转移,则,
\[dp_{i,j}=\max\{dp_{i-1,j}\}\;,j\in[1,max]
\]

列出来后,直接转移,时空双爆,60pts。

观察式子,发现可以用线段树来维护,1操作对应区间修改,2操作对应单点修改,3操作不用管,会直接覆盖。

复杂度 \(O(n\log n)\)

附基础dp

Code
#include<cstdio>
#include<algorithm>
#define MAX 100010
#define re register
#define int long long
using std::sort;
using std::unique;
using std::lower_bound;
namespace OMA
{
int n,cnt;
int tmp[MAX<<1];
int dp[6010][6010];
struct node
{
int a,b,w;
inline friend bool operator <(const node &a,const node &b)
{ return a.a+a.b<b.a+b.b; }
}p[MAX];
inline int max(int a,int b)
{ return a>b?a:b; }
inline int min(int a,int b)
{ return a<b?a:b; }
struct Segment_Tree
{
struct TREE
{
int l,r;
int val;
int lazy;
}st[MAX<<3];
inline int ls(int p)
{ return p<<1; }
inline int rs(int p)
{ return p<<1|1; }
inline void Push_up(int p)
{ st[p].val = max(st[ls(p)].val,st[rs(p)].val); }
inline void Push_down(int p)
{
if(st[p].lazy)
{
st[ls(p)].val += st[p].lazy;
st[ls(p)].lazy += st[p].lazy;
st[rs(p)].val += st[p].lazy;
st[rs(p)].lazy += st[p].lazy;
st[p].lazy = 0;
}
}
inline void build(int p,int l,int r)
{
st[p].l = l,st[p].r = r;
if(l==r)
{ return ; }
int mid = (l+r)>>1;
build(ls(p),l,mid),build(rs(p),mid+1,r);
}
inline void update1(int p,int l,int r,int val)
{
if(l>r)
{ return ; }
if(l<=st[p].l&&st[p].r<=r)
{ st[p].val += val,st[p].lazy += val; return ; }
Push_down(p);
int mid = (st[p].l+st[p].r)>>1;
if(l<=mid)
{ update1(ls(p),l,r,val); }
if(r>mid)
{ update1(rs(p),l,r,val); }
Push_up(p);
}
inline void update2(int p,int pos,int val)
{
if(st[p].l==st[p].r)
{ st[p].val = max(st[p].val,val); return ; }
Push_down(p);
int mid = (st[p].l+st[p].r)>>1;
if(pos<=mid)
{ update2(ls(p),pos,val); }
else
{ update2(rs(p),pos,val); }
Push_up(p);
}
inline int query(int p,int l,int r)
{
if(l<=st[p].l&&st[p].r<=r)
{ return st[p].val; }
Push_down(p);
int res = -1,mid = (st[p].l+st[p].r)>>1;
if(l<=mid)
{ res = max(res,query(ls(p),l,r)); }
if(r>mid)
{ res = max(res,query(rs(p),l,r)); }
return res;
}
}Tree;
struct stream
{
template<typename type>inline stream &operator >>(type &s)
{
int w=1; s=0; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ s = s*10+ch-'0'; ch=getchar(); }
return s*=w,*this;
}
}cin;
signed main()
{
//freopen("node.in","r",stdin);
cin >> n;
for(re int i=1,a,b,w; i<=n; i++)
{
p[i] = (node){(cin >> a,a),(cin >> b,b),(cin >> w,w)};
tmp[++cnt] = a,tmp[++cnt] = b;
}
sort(p+1,p+1+n);
sort(tmp+1,tmp+1+cnt);
cnt = unique(tmp+1,tmp+1+cnt)-tmp-1;
for(re int i=1; i<=n; i++)
{
p[i].a = lower_bound(tmp+1,tmp+1+cnt,p[i].a)-tmp;
p[i].b = lower_bound(tmp+1,tmp+1+cnt,p[i].b)-tmp;
//printf("%lld %lld\n",p[i].a,p[i].b);
}
Tree.build(1,1,cnt);
for(re int i=1; i<=n; i++)
{
int tmp = Tree.query(1,1,min(p[i].a,p[i].b));
Tree.update1(1,p[i].a,p[i].b,p[i].w);
Tree.update2(1,p[i].a,p[i].w+tmp);
}
printf("%lld\n",Tree.st[1].val);
/*int ans = 0;
for(re int i=1; i<=n; i++)
{
for(re int j=1; j<=n*2; j++)
{ dp[i][j] = dp[i-1][j]; }
for(re int j=p[i].a; j<=p[i].b; j++)
{ dp[i][j] = max(dp[i][j],dp[i-1][j]+p[i].w); }
for(re int j=1; j<=min(p[i].a,p[i].b); j++)
{ dp[i][p[i].a] = max(dp[i][p[i].a],dp[i-1][j]+p[i].w); }
}
for(re int i=1; i<=n; i++)
{
for(re int j=1; j<=n*2; j++)
{ ans = max(ans,dp[i][j]); }
//printf("\n");
}
printf("%lld\n",ans);*/
return 0;
}
}
signed main()
{ return OMA::main(); }

T3

跑 \(p\) 遍最短路,10pts。

正解:

跑个多源最短路,啥是多源最短路,就是有多个源点,在 \(dij\) 一开始往队列压点的操作时,把源点都压到里边,也就是本题的特殊点,再开个 \(pre\) 数组记录下每个点是由哪个源点扩展过来的,其他都是 \(dij\) 常规操作。

跑完一遍最短路,得到的是某个源点到当前点所构成的最短路径,具体是那个源点,则记录在了 \(pre\) 数组里。

对于答案,我们枚举每一条边,对于边的两个端点,如果其是由两个不同的源点扩展过来的,则可以得到当前两个源点通过 \(\{u,v\}\) 连接的距离 \(dis_{u}+dis_{v}+w\) 。 枚举取最小值即可。

画个图可能更好理解。

Code
#include<queue>
#include<cstdio>
#include<climits>
#include<cstring>
#include<algorithm>
#define MAX 200020
#define re register
#define int long long
#define INF 1145141919810
using std::sort;
using std::priority_queue;
int n,m,p;
int x[MAX];
int ans[MAX];
struct graph
{
int from;
int next;
int to;
int w;
}edge[MAX<<1];
int cnt=1,head[MAX];
inline void add(int u,int v,int w)
{ edge[++cnt] = (graph){u,head[u],v,w},head[u] = cnt; }
namespace MSSP
{
struct my
{
int dis,id;
inline friend bool operator <(const my &a,const my &b)
{ return a.dis>b.dis; }
};
priority_queue<my>q;
bool vis[MAX];
int dis[MAX],pre[MAX];
inline void dijkstra()
{
memset(dis,0x3f,sizeof(dis));
for(re int i=1; i<=p; i++)
{ q.push((my){dis[x[i]] = 0,pre[x[i]] = x[i]}); }
while(!q.empty())
{
int u = q.top().id; q.pop();
if(vis[u])
{ continue ; }
vis[u] = 1;
for(re int i=head[u],v,w; i; i=edge[i].next)
{
v = edge[i].to,w = edge[i].w;
if(dis[v]>dis[u]+w)
{
pre[v] = pre[u];
dis[v] = dis[u]+w;
q.push((my){dis[v],v});
}
}
}
}
}using namespace MSSP;
namespace OMA
{
struct stream
{
template<typename type>inline stream &operator >>(type &s)
{
int w=1; s=0; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
return s*=w,*this;
}
}cin;
inline int min(int a,int b)
{ return a<b?a:b; }
signed main()
{
//freopen("node.in","r",stdin);
//freopen("my.out","w"i,stdout);
cin >> n >> m >> p;
for(re int i=1; i<=p; i++)
{ cin >> x[i]; ans[x[i]] = INF; }
for(re int i=1,u,v,w; i<=m; i++)
{
cin >> u >> v >> w;
add(u,v,w),add(v,u,w);
}
dijkstra();
for(re int i=2,u,v,w; i<=cnt; i+=2)
{
u = edge[i].from,v = edge[i].to,w = edge[i].w;
if(pre[u]!=pre[v])
{
ans[pre[u]] = min(ans[pre[u]],dis[u]+dis[v]+w);
ans[pre[v]] = min(ans[pre[v]],dis[u]+dis[v]+w);
}
}
for(re int i=1; i<=p; i++)
{ printf("%lld\n",ans[x[i]]); }
return 0;
}
}
signed main()
{ return OMA::main(); }

T4

比较sb的模拟

Code
#include<cstdio>
#define MAX 100010
#define re register
namespace OMA
{
int t,n,top,sta[MAX];
int opt[MAX],cnt[MAX],sum,cot;
int rec[MAX],a[MAX][2],b[MAX][2];
signed main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
sum = cot = top = 0;
for(re int i=1; i<=n; i++)
{
char s[5];
scanf("%s",s);
if(s[0]=='$')
{ opt[i] = 1; scanf("%d",&cnt[i]); sta[++top] = i; }
if(s[0]=='+')
{ opt[i] = 2; }
if(s[0]=='-')
{ opt[i] = 3; }
}
if(!top)
{
int jud = 1;
for(re int i=1; i<=n; i++)
{ if(opt[i]==3){ jud ^= 1; } }
if(jud)
{ printf("consistent\n"); }
else
{ printf("inconsistent\n"); }
continue ;
}
for(re int i=1; i<=top; i++)
{
int fr = sta[i]+1,be,tot = 1,truth = 0,jud = 1;
if(i==top)
{ be = sta[1]; }
else
{ be = sta[i+1]; }
if(fr>n)
{ fr -= n; }
for(re int j=fr; j!=be; )
{
if(jud)
{ truth++; }
if(opt[j]==3)
{ jud ^= 1; }
j++,tot++;
if(j>n)
{ j -= n; }
}
rec[++cot] = cnt[be];
if(jud)
{
truth++;
a[cot][0] = tot-truth;
a[cot][1] = truth;
}
else
{
a[cot][0] = truth;
a[cot][1] = tot-truth;
}
b[rec[cot]][0] += a[cot][0];
b[rec[cot]][1] += a[cot][1];
sum += a[cot][0];
}
bool flag = false;
for(re int i=0; i<=n; i++)
{ if(sum-b[i][0]+b[i][1]==i){ flag = true; break ; } }
if(flag)
{ printf("consistent\n"); }
else
{ printf("inconsistent\n"); }
for(re int i=0; i<=n; i++)
{ a[i][0] = a[i][1] = b[i][0] = b[i][1] = 0; }
}
return 0;
}
}
signed main()
{ return OMA::main(); }

noip37的更多相关文章

随机推荐

  1. kong配置upstream实现简单的负载均衡

    目录 通过konga实现 1. 配置upstream 2. 配置Service发布 3. 配置Route,匹配规则 4. 验证结果 通过 Kong Admin API实现 1. 配置upstream ...

  2. Linux常用基础命令(二)

    Linux常用基础命令 一.-ls--列表显示目录内容 二.-alias--设置别名 三.-du--统计目录及文件空间占用情况 四.-mkdir--创建新目录 五.-touch--创建空文件 六.-l ...

  3. EXCEL:关键字有重复,其他信息一行多列显示

    =INDEX(A:A,SMALL(IF(MATCH($A$2:$A$13,$A$2:$A$13,0)=ROW($A$2:$A$13)-1,ROW($2:$13),4^8),ROW(1:1)))& ...

  4. session过期跳转到登陆页面并解决跳出iframe问题

    首先,先转载如下这篇博主写的关于后台系统使用iframe不能跳出的问题,地址:https://blog.csdn.net/xiaocen99/article/details/38521649 在ifr ...

  5. 前端开发入门到进阶第三集【Jsonp】

    /* $.ajax({ type : "get", url : "${loginInfo.SSO_BASE_URL }/user/token/" + token ...

  6. 数组去重汇总—v客学院技术分享

    上周基础班结束了数组的学习内容,这几天有时间整理了下几种比较常用的数组去重的方法供大家查阅!!!!! 话不多说,直接贴代码吧~~~~~~~ 欢迎大家指正,共同学习,一同进步!!! (php开发,web ...

  7. 微信小程序云开发-云开发环境配置工作

    一.注册小程序 打开[微信开发者工具],点击界面上的[注册],进入注册微信小程序页面.(也可以直接进入微信小程序注册地址:https://mp.weixin.qq.com/进行注册) 进入[小程序注册 ...

  8. Html模板引擎Handlerbars使用demo

    1.自定义demo <html> <head> <script src="./handlebars-v4.0.12.js"></scrip ...

  9. 第三篇 -- SpringBoot打包成jar包

    本篇介绍怎么将SprintBoot项目打包成jar包. 第一步:点击IDEA右侧的maven. 第二步:双击package,然后就会开始打包,当出现build success时,就打包成功了,一般在t ...

  10. Java 异步编程的几种方式

    前言 异步编程是让程序并发运行的一种手段.它允许多个事情同时发生,当程序调用需要长时间运行的方法时,它不会阻塞当前的执行流程,程序可以继续运行,当方法执行完成时通知给主线程根据需要获取其执行结果或者失 ...