为何我对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. spring中如何向一个单例bean中注入非单例bean

    看到这个题目相信很多小伙伴都是懵懵的,平时我们的做法大都是下面的操作 @Component public class People{ @Autowired private Man man; } 这里如 ...

  2. CF1458D Flip and Reverse[题解]

    Flip and Reverse 题目大意 给定一个 \(01\) 字符串,有机会进行若干次操作,对于每一次操作: 选择该字符串的子串,要求是该子串内包含数量相同的 \(0\) , \(1\) 字符. ...

  3. C语言:赋值

    #include <stdio.h> //=赋值运算符 //具有方向性,只能将赋值号右边的表达式的值给左边的变量 //赋值语句具有计算功能,赋值号右边可以是常量,变量或表达式都可以 //赋 ...

  4. idea使用maven下载jar包,出现证书校验问题问题,unable to find valid certification path to requested target

    每次从github上下载下来的项目都报如下错误could not transfer artifact org.springframework.boot:spring-boot-starter-pare ...

  5. 在Java web项目中防止用户注销后使用浏览器中的“后退”按钮返回注销前页面

    一背景 公司安全整改, 要求:系统中对于关键业务操作应确保使用浏览器"后退"功能无法回到上一步操作界面. 提供:凭证提供所有被检查系统关键业务操作后回退视频,视频显示关键业务操作后 ...

  6. java内存模型——重排序

    线程安全问题概括来说表现为三个方面:原子性,可见性和有序性. 在多核处理器的环境下:编译器可能改变两个操作的先后顺序:处理器可能不是完全依照程序的目标代码所指定的顺序执行命令:一个处理器执行的多个操作 ...

  7. 构建前端第9篇之(上)---Vue组件引入,使用

    张艳涛写于2020-1-25日 一.想写下vue引入组件和插件的理解 今天是星期一,周末也看俩两天,在这个几天了,比较迷,主要是从开始学习import指令开始的,import 是es6的语法, imp ...

  8. Apache ActiveMQ(cve-2015-5254)

    影响版本 Apache ActiveMQ 5.13.0之前5.x版本中存在安全漏洞 复现 使用工具执行命令 工具地址 https://github.com/matthiaskaiser/jmet/re ...

  9. 机器学习 - k-means聚类

    k-means简介 k-means是无监督学习下的一种聚类算法,简单说就是不需要数据标签,仅靠特征值就可以将数据分为指定的几类.k-means算法的核心就是通过计算每个数据点与k个质心(或重心)之间的 ...

  10. 记录21.08.04 — mybatis入门学习

    mybatis入门 mybatis简介 MyBatis 是一款优秀的持久层框架,它支持自定义 SQL.存储过程以及高级映射.MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工 ...