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\).综上, ...
随机推荐
- 数据结构逆向分析-Vector
数据结构逆向分析-Vector 这个应该是家喻户晓了的东西把,如果说C/C++程序员Vector都不用的话,可能就是一个不太好的程序员. Vector就是一个STL封装的动态数组,数组大家都知道是通过 ...
- Apache设置禁止访问网站目录
使用Apache作为Web服务器的时候,在当前目录下没有index.html|php等入口就会显示目录.让目录暴露在外面是非常危险的事. 找到Apache的配置文件 /etc/apache2/apac ...
- 监控linux服务器工具nmon的使用
做压测时,需要查看服务器中的cpu.内存变化,但由于服务器是linux环境,则需要监控linux服务器的工具,下面用到的工具是nmon. 1.安装nmon.在网上下载nmon安装包,在linux服务器 ...
- 51nod1355-斐波那契的最小公倍数【min-max容斥】
正题 题目链接:http://www.51nod.com/Challenge/Problem.html#problemId=1355 题目大意 定义\(f_i\)表示斐波那契的第\(i\)项,给出一个 ...
- requests之POST请求
上一节我们讲了GET请求,今天我们来讲讲POST请求. 学习一个新的模块,其实不用去百度什么的,直接用 help 函数就能查看相关注释和案例内容.如图所示,就是我们今天需要学习的内容. 1.用上面给的 ...
- Python列表操作常用API
1.列表的概念 (1)列表的定义 列表是Python中一种基本的数据结构.列表存储的数据,我们称为元素.在列表中的每个元素都会有一个下标来与之对应,第一个索引是0,第二个索引是1,依此类推的整数. 列 ...
- 前段---css
css主要是用来做如何显示html元素的 当浏览器读到一个样式表,它就会按照这个样式表来对文档做渲染 注意:每一个css样式表都是由两个部分组成的, 1,选择器 2,声明 声明又包括属性值和属性,每个 ...
- bzoj2038 小z的袜子 (莫队)
题目大意 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命-- 具体来说,小Z把这N只袜子从1到N编 ...
- 最新.NET MAUI有什么惊喜?
.NET 6 Preview 7 现已发布啦,我们为 .NET 多平台应用程序 UI (MAUI) 引入了所有的新布局.这是性能和可靠性的重大变化.我们很高兴我们还增加了一些关于accessibili ...
- 初探JavaScript PDF blob转换为Word docx方法
PDF转WORD为什么是历史难题 PDF 转Word 是一个非常非常普遍的需求,可谓人人忌危,为什么如此普遍的需求,却如此难行呢,还得看为什么会有这样的一个需求: PDF文档遵循iOS32000的规范 ...