ICPC Mid-Central USA Region 2019 题解
队友牛逼!带我超神!蒟蒻的我还是一点一点的整理题吧...
Dragon Ball I
这个题算是比较裸的题目吧....学过图论的大概都知道应该怎么做。题目要求找到七个龙珠的最小距离。很明显就是7个龙珠先后去的排列,然后用dijkstra预处理出来每个龙珠到所有其他的点的最短距离啊。最后dfs暴力枚举排列统计答案就行。这里有一些小的细节问题题目中最大的距离为2e9,所以0x3f可能有点不够,还真是细节决定成败啊,不亏我Wrong了一发!
//不等,不问,不犹豫,不回头.
#include<bits/stdc++.h>
#define _ 0
#define ls p<<1
#define db double
#define rs p<<1|1
#define P 1000000007
#define ll long long
#define INF 1000000000
#define get(x) x=read()
#define PLI pair<ll,int>
#define PII pair<int,int>
#define ull unsigned long long
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define fep(x,y,z) for(int x=y;x>=z;--x)
#define go(x) for(int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
using namespace std;
const int N=200010;
int n,m,link[N],id[10],tot,vis[N],d[10][N];
struct bian{ll y,v,next;}a[N<<1];
ll ans=1e18;
priority_queue<pair<ll,int> >q;
inline int read()
{
int x=0,ff=1;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*ff;
}
inline void add(int x,int y,int v)
{
a[++tot].y=y;a[tot].v=v;a[tot].next=link[x];link[x]=tot;
}
inline void dijkstra(int s)
{
rep(i,1,n) d[s][i]=2e9;
memset(vis,0,sizeof(vis));
d[s][id[s]]=0;
q.push({0,id[s]});
while(q.size())
{
int x=q.top().second;q.pop();
if(vis[x]) continue;
vis[x]=1;
for(int i=link[x];i;i=a[i].next)
{
int y=a[i].y;
if(d[s][y]>d[s][x]+a[i].v)
{
d[s][y]=d[s][x]+a[i].v;
q.push({-d[s][y],y});
}
}
}
}
inline void dfs(int now,int cnt,ll s)
{
if(cnt==7)
{
ans=min(ans,s);
return;
}
rep(i,1,7)
{
if(!vis[i])
{
vis[i]=1;
dfs(i,cnt+1,s+d[now][id[i]]);
vis[i]=0;
}
}
}
int main()
{
//freopen("1.in","r",stdin);
get(n);get(m);
rep(i,1,m)
{
int get(x),get(y),get(v);
add(x,y,v);add(y,x,v);
}
id[0]=1;
rep(i,1,7) get(id[i]);
rep(i,0,7) dijkstra(i);
rep(i,1,7)
{
if(d[0][id[i]]==2e9)
{
puts("-1");
return 0;
}
}
memset(vis,0,sizeof(vis));
dfs(0,0,0);
putl(ans);
return (0^_^0);
}
//以吾之血,铸吾最后的亡魂.
Farming Mars
这个算是比较裸的数据结构的题了...简化下题意就是:给你一个序列,有询问,问一个区间中有没有一个数的个数大于等于区间的一半(向上取整).先不想那么多,看到10000的范围,我这暴脾气,先打个暴力试试,\(O(n^2)\)闯天下啊,真过了,赛后就不能这样敷衍了事了。仔细想想不就是权值计数吗?区间查询最大值,写个主席树不就行了?...太水了题...不对不对,这不太行啊,主席树没法维护区间最大值啊...假了假了假了...原来小丑竟是我自己...等等等..等等,这个题问的不是区间众数的次数吗?分块啊!还是分块大法好!莫队!所有\(O(n\sqrt n)\)的数据结构都行。
先放个暴力的代码:
//不等,不问,不犹豫,不回头.
#include<bits/stdc++.h>
#define _ 0
#define ls p<<1
#define db double
#define rs p<<1|1
#define P 1000000007
#define ll long long
#define INF 1000000000
#define get(x) x=read()
#define PLI pair<ll,int>
#define PII pair<int,int>
#define ull unsigned long long
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define fep(x,y,z) for(int x=y;x>=z;--x)
#define go(x) for(int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
using namespace std;
const int N=10010;
int n,m,a[N],ct[N],num;
db b[N],t[N];
inline int read()
{
int x=0,ff=1;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*ff;
}
inline int find(db s) {return lower_bound(b+1,b+num+1,s)-b;}
inline void init()
{
get(n);get(m);
rep(i,1,n) cin>>t[i],b[i]=t[i];
sort(b+1,b+n+1);
num=unique(b+1,b+n+1)-b-1;
rep(i,1,n) a[i]=find(t[i]);
}
int main()
{
//freopen("1.in","r",stdin);
init();
rep(i,1,m)
{
int get(l),get(r);
rep(j,l,r) ct[a[j]]++;
bool flag=false;
rep(j,l,r) if(ct[a[j]]>=((r-l+1)/2)+1)
{
flag=true;
break;
}
if(flag) puts("usable");
else puts("unusable");
rep(j,l,r) ct[a[j]]=0;
}
return (0^_^0);
}
//以吾之血,铸吾最后的亡魂.
回滚莫队的代码,分块由于前不久练过,就不再写一遍了,真的很费脑细胞...
//不等,不问,不犹豫,不回头.
#include<bits/stdc++.h>
#define _ 0
#define ls p<<1
#define db double
#define rs p<<1|1
#define P 1000000007
#define ll long long
#define INF 1000000000
#define get(x) x=read()
#define PLI pair<ll,int>
#define PII pair<int,int>
#define ull unsigned long long
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define fep(x,y,z) for(int x=y;x>=z;--x)
#define go(x) for(int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
using namespace std;
const int N=10010;
int a[N],num,n,m,ans[N];
int belong[N],bl[N],br[N],block,bnum,cnt1[N],cnt2[N];
db t[N],b[N];
struct wy{int l,r,id;}q[N];
inline int read()
{
int x=0,ff=1;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*ff;
}
inline int find(db s) {return lower_bound(b+1,b+num+1,s)-b;}
inline void build()
{
block=sqrt(n);bnum=n/block;
if(n%block) bnum++;
rep(i,1,n) belong[i]=(i-1)/block+1;
rep(i,1,bnum) bl[i]=(i-1)*block+1,br[i]=i*block;
br[bnum]=n;
}
inline bool cmp(wy a,wy b)
{
return (belong[a.l]!=belong[b.l]?belong[a.l]<belong[b.l]:a.r<b.r);
}
inline void init()
{
get(n);get(m);
rep(i,1,n) cin>>t[i],b[i]=t[i];
sort(b+1,b+n+1);
num=unique(b+1,b+n+1)-b-1;
rep(i,1,n) a[i]=find(t[i]);
rep(i,1,m) get(q[i].l),get(q[i].r),q[i].id=i;
build();
sort(q+1,q+m+1,cmp);
}
inline void solve()
{
int i=1;
rep(j,1,bnum)
{
int now=0;
int l=br[j]+1,r=br[j];
memset(cnt1,0,sizeof(cnt1));
for(;i<=m&&belong[q[i].l]==j;++i)
{
int temp;
int ql=q[i].l,qr=q[i].r;
if(belong[ql]==belong[qr])
{
temp=0;
rep(k,ql,qr) cnt2[a[k]]=0;
rep(k,ql,qr) cnt2[a[k]]++,temp=max(temp,cnt2[a[k]]);
ans[q[i].id]=(temp>=(qr-ql+1)/2+1?1:0);continue;
}
while(r<qr) cnt1[a[++r]]++,now=max(now,cnt1[a[r]]);
temp=now;
while(l>ql) cnt1[a[--l]]++,now=max(now,cnt1[a[l]]);
ans[q[i].id]=(now>=(qr-ql+1)/2+1?1:0);
now=temp;
while(l<br[j]+1) cnt1[a[l++]]--;
}
}
rep(i,1,m)
{
if(ans[i]) puts("usable");
else puts("unusable");
}
}
int main()
{
// freopen("1.in","r",stdin);
init();
solve();
return (0^_^0);
}
//以吾之血,铸吾最后的亡魂.
Sum and Product
队友牛逼带我超神....
首次看这个题,题意很好理解就是找到有多少个子区间,使得这个区间里所有元素的乘积等于和。...
看起来好复杂...但仔细思考一下,全部元素的乘积,...,这玩意是不是有点大....连续64个2想乘就爆longlong了,那全部元素的和的大小范围呢?\(n\)是\(2e5\),\(a_i\)是\(1e9\),也就是说这里的元素和最大值为\(2e14\),那乘积超过这个不就一定不合法了吗?那直接暴力,然后break。T了....为啥会T啊...昂,对了序列中可能有很多的1使得乘积长时间不变,那我们考虑能不能直接跳过这些乘积,直接和有效的数组想乘,我这里记了一个id[i]数组表示i之后一个非1的位置,然后固定左端点,寻找去合法右端点的数目,由于中间全部是1,累乘的结果很好维护,累加的话根据下标计算也很容易。考虑这之间有没有可能会出现合法的右端点,由于全部是1,所以乘积不变,和一直加,若之前和<乘积。并且这里1的个数又足够多的话,我们就能在一堆1中实现和=积的情况,并且最多一次,因为相等之后,和还往上加,积就不变,一定不和法,那这样就好办了,我们在跳的一堆1中看有没有符合条件的,跳过后看有没有符合条件。这样最多跳64次。总复杂度为\(O(nlogn)\)
注意这里用除法代替乘法,避免爆long long.
//不等,不问,不犹豫,不回头.
#include<bits/stdc++.h>
#define _ 0
#define ls p<<1
#define db double
#define rs p<<1|1
#define P 1000000007
#define ll long long
#define INF 1000000000
#define get(x) x=read()
#define PLI pair<ll,int>
#define PII pair<int,int>
#define ull unsigned long long
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define fep(x,y,z) for(int x=y;x>=z;--x)
#define go(x) for(int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
using namespace std;
const int N=2e5+10;
const ll MAX=2e14;
int n,a[N],id[N],now;
inline int read()
{
int x=0,ff=1;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*ff;
}
int main()
{
//freopen("1.in","r",stdin);
get(n);
rep(i,1,n) get(a[i]);
int now=n;
fep(i,n,1)
{
id[i]=now;
if(a[i]!=1) now=i;
}
id[n]=0;
int ans=0;
rep(i,1,n) //统计每个左端点合法的右端点
{
ll mt=a[i],sm=a[i];
now=i;
while(id[now])
{
if(MAX/mt<a[id[now]]) break;
if(sm<mt&&sm+(id[now]-now-1)>=mt) ++ans;
mt=mt*a[id[now]];
sm=sm+a[id[now]]+(id[now]-now-1);
if(mt==sm) ++ans;
now=id[now];
}
}
put(ans);
return (0^_^0);
}
//以吾之血,铸吾最后的亡魂.
J True/False Worksheet
这个题主要是思路被限制住了,想到并查集后就完全想着用数学方法解决问题了...
其实看到\(n\)为\(5000\)的时候就可以考虑\(dp\)的写法了。
首先考虑无解的情况,就是一个要求不相同的区间里面的数被迫相同,我们直接预处理就行。
考虑\(DP\)怎样设状态,由于题目中的限制条件是一个区间必须是相同或不能全部相同,所以我们状态中就应该能体现这个相同与否的状态。考虑设\(f[i][j]\)表示从第\(j\)位到第\(i\)位都相同,且到\(i\)位结尾的方案数。转移时可以想不用考虑限制条件。当第\(i\)个和第\(i-1\)个保持一样时\(f[i][j]=f[i-1][j]\),当第\(i\)个和\(i-1\)不一样时,\(f[i][i]=\)\(\sum_{k=1}^{i-1}{f[i-1][k]}\)。那么接下来考虑相同的限制条件,比如说从l到i都必须是相同的,那么\(f[i][1],f[i][2]...f[i][l]\)都是合法的状态,考虑不相同的限制条件,比如从l到i都不相同,那么从\(f[i][l+1],f[i][l+2],...,f[i][i]\)都是合法的,既然如此我们就可以得知每个i的所有合法状态有哪些即\(diff[i]+1-same[i]\)这些状态是合法的。至于当\(f[i][i]\)转移时我们可以对\(i-1\)的转态枚举时,可以直接从\(1\)到\(i-1\),因为在\(i-1\)时我们只保存了合法的状态。同理在统计答案时,我们可以直接求和,不必在乎是否合法,因为我们只保存了合法的状态的值,能转移过来的一定是合法的。
//不等,不问,不犹豫,不回头.
#include<bits/stdc++.h>
#define _ 0
#define ls p<<1
#define db double
#define rs p<<1|1
#define P 1000000007
#define ll long long
#define INF 1000000000
#define get(x) x=read()
#define PLI pair<ll,int>
#define PII pair<int,int>
#define ull unsigned long long
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define fep(x,y,z) for(int x=y;x>=z;--x)
#define go(x) for(int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
using namespace std;
const int N=5010;
int n,m,f[N][N];//f[i][j]表示从j到i都相同的方案数
int same[N],diff[N];
bool flag=true;
char c[N];
inline int read()
{
int x=0,ff=1;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*ff;
}
inline void init()
{
get(n);get(m);
rep(i,1,n) same[i]=i;
rep(i,1,m)
{
int get(x),get(y);
scanf("%s",c+1);
if(c[1]=='s') same[y]=min(same[y],x);
else diff[y]=max(diff[y],x);
}
rep(i,1,n) if(diff[i]>=same[i]) flag=false;
if(!flag) puts("0");
}
inline void solve()
{
f[1][1]=2;
rep(i,2,n)
{
rep(j,diff[i]+1,same[i]) f[i][j]=(f[i][j]+f[i-1][j])%P;
if(same[i]==i)
{
rep(j,1,i-1) f[i][i]=(f[i][i]+f[i-1][j])%P;
}
}
int ans=0;
rep(i,1,n) ans=(ans+f[n][i])%P;
put(ans);
}
int main()
{
//freopen("1.in","r",stdin);
init();
if(flag) solve();
return (0^_^0);
}
//以吾之血,铸吾最后的亡魂.
ICPC Mid-Central USA Region 2019 题解的更多相关文章
- 2016 ICPC Mid-Central USA Region J. Windy Path (贪心)
比赛链接:2016 ICPC Mid-Central USA Region 题目链接:Windy Path Description Consider following along the path ...
- ICPC North Central NA Contest 2018
目录 ICPC North Central NA Contest 2018 1. 题目分析 2. 题解 A.Pokegene B.Maximum Subarrays C.Rational Ratio ...
- Hello 2019题解
Hello 2019题解 题解 CF1097A [Gennady and a Card Game] map大法好qwq 枚举每一个的第\(1,2\)位判是否与给定的重复即可 # include < ...
- ICPC World Finals 2019 题解
[A]Azulejos 题意简述: 有两排瓷砖,每排都有 \(n\) 个,每个瓷砖有高度 \(h_i\) 和价格 \(p_i\) 两种属性. 你需要分别重新排列这两排瓷砖,使得同一排的瓷砖满足价格不降 ...
- Code Chef February Challenge 2019题解
传送门 \(HMAPPY2\) 咕 话说这题居然卡\(scanf\)的么??? int T;cin>>T; while(T--){ cin>>n>>a>> ...
- CodeChef March Challenge 2019题解
传送门 \(CHNUM\) 显然正数一组,负数一组 for(int T=read();T;--T){ n=read(),c=d=0; fp(i,1,n)x=read(),x>0?++c:++d; ...
- 2016ACM/ICPC亚洲区大连站现场赛题解报告(转)
http://blog.csdn.net/queuelovestack/article/details/53055418 下午重现了一下大连赛区的比赛,感觉有点神奇,重现时居然改了现场赛的数据范围,原 ...
- Code Chef January Challenge 2019题解
传送门 \(div2\)那几道题不来做了太水了-- \(DPAIRS\) 一个显然合法的方案:\(A\)最小的和\(B\)所有连,\(A\)剩下的和\(B\)最大的连 算了咕上瘾了,咕咕咕 const ...
- CodeChef April Challenge 2019题解
传送门 \(Maximum\ Remaining\) 对于两个数\(a,b\),如果\(a=b\)没贡献,所以不妨假设\(a<b\),有\(a\%b=a\),而\(b\%a<a\).综上, ...
随机推荐
- python IO流操作
python IO流操作 学习完本篇,你将会独立完成 实现操作系统中文件及文件目录的拷贝功能. 将目标图片拷贝到指定的目录中 实现一个自动阅卷程序, Right.txt保存正确答案,xx(学生姓名). ...
- dede调用文章内第一张原始图片(非缩略图)的实现方法
第一步,修改include/extend.func.php文件,最下面插入函数,查询的是文章附加表,如需查询图片集什么的,改表名即可 //取原图地址 function GetFirstImg($arc ...
- Jmeter系列(28)- 性能指标(1) | 常见性能指标
TPS 概念 TPS (transaction per second):意思是每秒事务数,具体事务的定义,都是人为的,可以一个接口.多个接口.一个业务流程等等.一个事务是指事务内第一个请求发送到接收到 ...
- AVS 端能力之音频播放模块
功能简介 音频播放 音频流播放 URL文件播放 播放控制 播放 暂停 继续 停止 其它功能(AVS服务器端实现) 支持播放列表 支持上一首下一首切换 支持电台 事件指令集 AudioPlayer 端能 ...
- kubeadm 命令简介
kubeadm 命令 kubeadm init 启动一个kubernetes主节点 kubeadm join 启动一个kubernetes工作节点并加入到集群中 kubeadm upgrade 更新一 ...
- P5305-[GXOI/GZOI2019]旧词【树链剖分,线段树】
正题 题目链接:https://www.luogu.com.cn/problem/P5305 题目大意 给一棵有根树和\(k\),\(Q\)次询问给出\(x,y\)求 \[\sum_{i=1}^{x} ...
- C语言数组实现三子棋
C语言实现三子棋(通过数组) 需要包含的头文件 #include <stdio.h> #include <stdlib.h> #include <time.h> 创 ...
- Java通过socket和DTU,RTU连接工业传感器通信
现在做DTU传感器监测数据一块,给大家分享如何通过socket技术连接到DTU,并能和DTU下面的传感器通信的,分享一下自己的心得和体会. 总体架构图 先来看下整体网络结构图. 工业名称解释 传感器: ...
- mysql增删改查——条件查询+模糊查询
条件查询一般是 = 等于 >大于 <小于 >=大于等于 <=小于等于 <>区间 between and区间 or并且 and或者 in包含 like模糊查询 实例, ...
- 洛谷3176 [HAOI2015]数字串拆分 (矩阵乘法+dp)
qwq真的是一道好题qwq自己做基本是必不可能做出来的. 首先,如果这个题目只是求一个\(f\)数组的话,那就是一道裸题. 首先,根据样例 根据题目描述,我们能发现其实同样数字的不同排列,也是属于不同 ...