“2018宁夏邀请赛 ” 兼 “The 2019 Asia Yinchuan First Round Online Programming”
------------7题弟弟,被各位半小时13题的大佬打惨了(滑稽)----------
签到题就不写了。
F :Moving On (1247ms)
题意:给定大小为N的带点权,带边权的完全图,N<200。 然后Q次询问,每次给出(u,v,w),让你求在除了起点终点的其他途经点的点权都<=w的条件下的最短路。
思路:可以离线做的话,显然就是需要排序了。 然后想到floyd就是一个用点更新的最短路算法。 那么我们把floyd的第一层按点权排个序即可。 那么第k层的dis[i][j],就表示途经点都<=w[k]的最短路。 为了方便,这里所有的点权和询问的w都离散化了。 (比赛因为没有初始化WA了半天,哭)(网上看了其他人的写法大都是三维的,显然没必要,很明显是滚动的,在可以离线的情况下,第一维没什么用)。
#include<bits/stdc++.h>
#define pii pair<int,int>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
const int maxm=;
int mp[maxn][maxn],b[maxn],tot,ans[maxm];
struct in{
int u,v,w,id;
};
vector<in>G[maxn];
pii a[maxn];
int main()
{
int T,N,M,C=;
scanf("%d",&T);
while(T--){
scanf("%d%d",&N,&M);
rep(i,,N) scanf("%d",&a[i].first),a[i].second=i;
rep(i,,N) b[i]=a[i].first;
sort(b+,b+N+);
tot=unique(b+,b+N+)-(b+);
rep(i,,tot) G[i].clear();
rep(i,,N) a[i].first=lower_bound(b+,b+tot+,a[i].first)-b;
sort(a+,a+N+);
rep(i,,N) rep(j,,N) scanf("%d",&mp[i][j]);
rep(i,,M) {
in t;
scanf("%d%d%d",&t.u,&t.v,&t.w);
ans[i]=mp[t.u][t.v];
t.w=upper_bound(b+,b+tot+,t.w)-b;
t.w--; t.id=i;
G[t.w].push_back(t);
}
rep(k,,N) {
int tk=k; while(tk+<=N&&a[tk+].first==a[k].first) tk++;
rep(p,k,tk) {
rep(i,,N)
rep(j,,N){
int kk=a[p].second;
mp[i][j]=min(mp[i][j],mp[i][kk]+mp[kk][j]);
}
}
for(int i=;i<G[a[k].first].size();i++){
in t=G[a[k].first][i];
ans[t.id]=min(ans[t.id],mp[t.u][t.v]);
}
k=tk;
}
printf("Case #%d:\n",++C);
rep(i,,M) printf("%d\n",ans[i]);
}
return ;
}
G:Factories (1036ms)
题意:给定一个大小为N的无根树,让你选K个叶子,使得两两间距离和最短。 (N<1e5, K<100);
思路:这类题可能会想到换根DP,然后这里想了想没必要 。 如果有度数大于1的,它就可以作为根,然后就是一个树上背包题,而谁作为根,效果是一样的,所以没必要换根DP。 然后发现想不出O(NK)的写法,所以瞎交了一发O(NK^2)。 居然过了。 玄学。
update:这样实际的复杂度是O(NK)的。
参考:https://www.cnblogs.com/ouuan/p/BackpackOnTree.html
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
const ll inf=1LL<<;
int Laxt[maxn],Next[maxn<<],To[maxn<<],len[maxn<<],cnt;
int ind[maxn],rt,sz[maxn],K;
void add(int u,int v,int w){
Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; len[cnt]=w;
}
ll dp[maxn][],ans;
void read(int &x){
x=; char c=getchar();
while(c>''||c<'') c=getchar();
while(c>=''&&c<='') x=x*+c-'',c=getchar();
}
void dfs(int u,int f)
{
sz[u]=; int leaf=; dp[u][]=;
for(int i=Laxt[u];i;i=Next[i]){
int v=To[i]; if(v==f) continue;
leaf=; dfs(v,u);
for(int k=sz[u];k>=;k--){
for(int j=min(K-k,sz[v]);j>=;j--){
dp[u][k+j]=min(dp[u][k+j],dp[u][k]+dp[v][j]+1LL*(K-j)*j*len[i]);
}
}
sz[u]+=sz[v];
}
if(leaf) sz[u]=,dp[u][]=;
if(sz[u]>=K) ans=min(ans,dp[u][K]);
}
int main()
{
int T,N,C=,u,v,w;
scanf("%d",&T);
while(T--){
scanf("%d%d",&N,&K);
rep(i,,N) Laxt[i]=; cnt=;
rep(i,,N+) rep(j,,K) dp[i][j]=inf; ans=inf;
rep(i,,N) ind[i]=;
rep(i,,N-){
read(u); read(v); read(w);
add(u,v,w); add(v,u,w);
ind[u]++; ind[v]++;
}
if(N==||K<=) ans=;
else if(N==) ans=len[];
else {
rep(i,,N) if(ind[i]>) {
rt=i; break;
}
dfs(rt,);
}
printf("Case #%d: %lld\n",++C,ans);
}
return ;
}
I: Bubble Sort
题意:如果K轮冒泡排序后LIS>=N-1,则说这个排列是ok的,给次给出N和K,问有多少个是ok的。
思路:不难想到可以DP做。
(代码晚点再放。
K:Vertex Covers (1060ms)
题意:给定N点M边的无向图,每个点有点权。 点覆盖表示某个点集S{}覆盖了所有的边,其贡献是点权S之积。 现在让你求所有的贡献之和。N<36,保证无重边,自环。
思路:点覆盖的问题,而且N比较小,不难想到状压。 可以这里N最大为36,显然还需要一个折半枚举,然后想办法合并两边。
那么我们把点分为L,R两个集合。 那么边有三类: 1,两端点在L中; 2,两端点在R中; 3,两端点在L和R中各一个。
那么显然,对于1类边,两个端点至少一个要选; 对于2类边同理; 对于第3类边, 如果L中没选,那么R中必选,即补集的超集,而超集我们可以用高维前缀和搞定。 所以这题就完了。 (那些100ms跑出来的人都是神仙吧)
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
int a[maxn],sum[maxn],ltl[],ltr[],rtr[],Mod;
void MOD(int &x){ if(x>=Mod) x-=Mod;}
int main()
{
int T,N,M,u,v,C=;
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&N,&M,&Mod);
rep(i,,N-) scanf("%d",&a[i]);
rep(i,,N-) ltl[i]=ltr[i]=rtr[i]=;
int L=(N+)/, R=N-L, ans=;
rep(i,,M){
scanf("%d%d",&u,&v);
u--, v--;
if(u>v) swap(u,v);
if(u<L){
if(v<L) ltl[u]|=(<<v);
else ltr[u]|=(<<(v-L));
}
else rtr[u]|=(<<(v-L));
}
rep(i,,(<<R)-){
int res=;
rep(j,,R-){
if(i&(<<j)) res=1LL*res*a[j+L]%Mod;
else {
res=res*((rtr[j+L]|i)==i);
if(!res) break;
}
}
sum[i]=res;
}
rep(i,,R-) {
rep(j,,(<<R)-) {
if(!(j&(<<i))) MOD(sum[j]+=sum[j|(<<i)]);
}
}
rep(i,,(<<L)-){
int res=,need=;
rep(j,,L-) {
if(i&(<<j)) res=1LL*res*a[j]%Mod;
else {
res=res*((ltl[j]|i)==i),need|=ltr[j];
if(!res) break;
}
}
MOD(ans+=1LL*res*sum[need]%Mod);
}
printf("Case #%d: %d\n",++C,ans);
}
return ;
}
L:Continuous Intervals (1075ms)
题意:给定长度为N的序列,求有多少个子区间,满足这个区间排序后,相邻的数相差<=1;
思路:即是问,有多少个区间满足max-min+1==cnt,max和min是区间最大最小值,cnt是区间种类数。
分治吗? 没法分,没法治。 启发式分治吗?没法找mid。
所以试一试暴力? 我们枚举右端点R,那么就是统计多少个L合法。 假设得到了[1,R-1]的所有信息,现在加入一个R进去,
1,可能会对某些区间的极值产生影响; 2,可能会对某个区间的cnt产生影响。
我们只需要维护好每个L点的信息,用来表示后缀的极值和cnt即可。
如何维护区间极值:线段树。
如何减少维护次数:单调队列+lazy。
对于cnt:影响的只有[laxt[a[R]]+1,R]这个区间。
所以综上,只需要维护三个lazy即可。 然后右移R,修改线段树,统计有多少个max-min+1=cnt,即max-min-cnt==-1的区间即可。
由于有三种变量,所以维护三个lazy会比较麻烦。 我们直接维护一个差值,这样可以统一,变成每次都是维护一个差值可以了。
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
int Mn[maxn],lazy[maxn],sum[maxn],a[maxn];
int q1[maxn],t1,q2[maxn],t2;
map<int,int>mp;
void build(int Now,int L,int R)
{
sum[Now]=R-L+; Mn[Now]=lazy[Now]=;
if(L==R) return ; int Mid=(L+R)>>;
build(Now<<,L,Mid);
build(Now<<|,Mid+,R);
}
void pushdown(int Now)
{
if(!lazy[Now]) return ;
Mn[Now<<]+=lazy[Now]; Mn[Now<<|]+=lazy[Now];
lazy[Now<<]+=lazy[Now]; lazy[Now<<|]+=lazy[Now];
lazy[Now]=;
}
void pushup(int Now)
{
Mn[Now]=min(Mn[Now<<],Mn[Now<<|]);
if(Mn[Now<<]==Mn[Now<<|]) sum[Now]=sum[Now<<]+sum[Now<<|];
else if(Mn[Now<<]<Mn[Now<<|]) sum[Now]=sum[Now<<];
else sum[Now]=sum[Now<<|];
}
void update(int Now,int L,int R,int l,int r,int v)
{
if(l>r) return ;
if(L==R) {
Mn[Now]+=v;
return ;
}
if(l<=L&&r>=R){
Mn[Now]+=v; lazy[Now]+=v;
return ;
}
int Mid=(L+R)>>; pushdown(Now);
if(l<=Mid) update(Now<<,L,Mid,l,r,v);
if(r>Mid) update(Now<<|,Mid+,R,l,r,v);
pushup(Now);
}
int main()
{
int T,N,C=; ll ans;
scanf("%d",&T);
while(T--){
scanf("%d",&N);
rep(i,,N) scanf("%d",&a[i]);
build(,,N);
t1=t2=; ans=; mp.clear();
rep(i,,N){
update(,,N,i,i,-);
while(t1&&a[i]>=a[q1[t1]]){
update(,,N,q1[t1-]+,q1[t1],a[i]-a[q1[t1]]);
t1--;
}
q1[++t1]=i; while(t2&&a[i]<=a[q2[t2]]){
update(,,N,q2[t2-]+,q2[t2],a[q2[t2]]-a[i]);
t2--;
}
q2[++t2]=i; update(,,N,mp[a[i]]+,i-,-); mp[a[i]]=i;
ans+=sum[];
}
printf("Case #%d: %lld\n",++C,ans);
}
return ;
}
“2018宁夏邀请赛 ” 兼 “The 2019 Asia Yinchuan First Round Online Programming”的更多相关文章
- [The 2019 Asia Yinchuan First Round Online Programming] D Take Your Seat
也许更好的阅读体验 \(\mathcal{Description}\) 原题链接 题目大意 该题目有两个问题 \(Task\ 1\),有\(n\)个人\(n\)个座位,每个人都有一个对应的座位,每个人 ...
- The 2019 Asia Yinchuan First Round Online Programming F. Moving On
t题目链接:https://nanti.jisuanke.com/t/41290 思路:题目意思很容易想到floyd,但是由于危险度的限制,我们该怎么跑floyd呢. 一开始理解错题目了,以为u-&g ...
- The 2019 Asia Nanchang First Round Online Programming Contest
传送门 A. Enju With math problem 题意: 给出\(a_1,\cdots,a_{100}\),满足\(a_i\leq 1.5*10^8\). 现在问是否存在一个\(pos\), ...
- The 2019 Asia Nanchang First Round Online Programming Contest C(cf原题,线段树维护矩阵)
题:https://nanti.jisuanke.com/t/41350 分析:先将字符串转置过来 状态转移,因为只有5个状态,所以 i 状态到 j 状态的最小代价就枚举[i][k]->[k][ ...
- The 2019 Asia Nanchang First Round Online Programming Contest E. Magic Master
题目链接:https://nanti.jisuanke.com/t/41352 题目意思还是好理解的,看过的人不多,感觉是被通过量吓到了.其实就是个水题,反向模拟就好了, 用队列模拟,反向模拟,它要放 ...
- The 2019 Asia Nanchang First Round Online Programming Contest B. Fire-Fighting Hero
题目链接:https://nanti.jisuanke.com/t/41349 题意:有一个灭火英雄,和一个灭火团队,一个人与一个团队比较. 灭火英雄到其他灭火点的最短路最大值,与一个团队到其他灭火点 ...
- The 2019 Asia Nanchang First Round Online Programming Contest The Nth Item
The Nth Item 思路: 先用特征根法求出通向公式,然后通向公式中出现了\(\sqrt{17}\),这个可以用二次剩余求出来,然后可以O(\(log(n)\))求出. 但是还不够,我们先对\( ...
- H. The Nth Item(The 2019 Asia Nanchang First Round Online Programming Contest)
题意:https://nanti.jisuanke.com/t/41355 给出N1,计算公式:A=F(N)Ni=Ni-1 ^ (A*A),F为类斐波那契需要矩阵快速幂的递推式. 求第k个N. 思路: ...
- E.Magic Master(The 2019 Asia Nanchang First Round Online Programming Contest)
直接模拟orhttps://blog.csdn.net/liufengwei1/article/details/100643831
随机推荐
- serializers进阶
文章出处 https://www.cnblogs.com/pyspark/p/8607801.html [01]前言 serializers是什么?官网是这样的”Serializers all ...
- Sitecore 9 您应该了解的所有新功能和变化
信不信由你,当我谈论Sitecore时,我感到非常兴奋.这是一个充满潜力和机遇的伟大平台 如果你能想象一个刚刚进行过一次双重训练的人,一个特大号的星巴克,并且刚刚在创纪录的时间内完成了中国忍者勇士的障 ...
- word 转 pfd
转自: https://www.cnblogs.com/qiwu1314/p/6101400.html demo: public class Doc2Pdf { public static boole ...
- tkinter添加背景音乐
一.问题利用tkinter来写一个游戏,添加一个背景音乐提高可玩性. 二.解决1.安装pygame首先是利用pygame的一个播放流:[pip install pygame]来完成pygame的安装. ...
- HDU校赛 | 2019 Multi-University Training Contest 5
2019 Multi-University Training Contest 5 http://acm.hdu.edu.cn/contests/contest_show.php?cid=852 100 ...
- AGC035
Contest Page A 唯一会做的题/kk 题目相当于要求相邻三个的异或和为\(0\). 当我们放入了三个数\(a,b,c\)时,接下来的放入顺序显然一定是\(a,b,c,a,b,c,...\) ...
- 2019 翔通动漫java面试笔试题 (含面试题解析)
本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.翔通动漫等公司offer,岗位是Java后端开发,因为发展原因最终选择去了翔通动漫,入职一年时间了,也成为了面 ...
- Springboot - java.lang.IllegalStateException: Failed to load property source from location 'classpath:/application.yml'
Caused by: org.yaml.snakeyaml.scanner.ScannerException: while scanning a simple key in 'reader', lin ...
- OpenSessionInViewFilter 的配置及替代方案
OpenSessionInViewFilter 的配置及替代方案 博客分类: hibernate OpenSessionInViewFilter 的配置及替代方案 Spring 为我们提供了一个叫做 ...
- set_lb
修改lb权重,通知钉钉 前提需要安装阿里的核心库 #!/usr/local/python-3.6.4/bin/python3 #coding=utf-8 from aliyunsdkcore.clie ...