垫底之旅
2016-2017 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2016)
看的题 但没做出来 感觉都在能力范围之内 就是没想到
A: 倒跑并查集
也蛮难写的 也要把一个点hash成一个值 就是二维变一维嘛
这 怎么想的到
B:tire树上的bfs
tire树都不知道是是什么 你让我怎么做
C:对一副乱序的扑克牌求排有序的最小_交换相邻元素的_操作个数
首先数据规模很小 (最多52张牌嘛)
先想想最暴力的做法咯 就对于给定的一副牌
排序的结果无非是 4!(花色全排列)*2^4(顺序和倒序)种结果 384
例如样例1
2h Th 8c Qh
所有的可能性 1.2h Th Qh 8c
2.8c 2h Th Qh
还有倒序的,不写了
那验证每一种初态到给定态的检查的方法复杂度要多少啊?
不知道啊 卡住了啊 看题解。。。
怎么就LCS了拉 我怎么不知道什么意思啊?
那就考虑一个更简单的模型
一串乱序的数字序列 需要相邻元素交换几次才能变为不下降序列?
艹 不需要相邻元素 随便交换 艹艹艹艹艹 又tm读错题了
Sorting is done by moving one card at a time fromits current position to a new position in the hand, atthe start, end, or in between two adjacent cards. Whatis the smallest number of moves required to sort agiven hand of cards?
枚举4!种排列组合 和2^4 正序 倒序 暴力求解
求出最大的LCS就可以拉
有个小tips:A是王牌 是最大的。。。。wa了好几发 读题读题
看错题太蠢了
F
推公式 排列组合题 ,没什么难度 但我推不出
H
见过一道差不多的,没去写,亏了。找了半个小时没找到 算了。
额 我错了 看了那么久 还是看不懂
抄一遍代码 找感觉吧
额 又看了一遍题目。知道了,感觉有意思。
大意是:给n个矩形,让他们一个一个往上叠,约束条件是 宽严格递减(矩形可以旋转,所以长宽可以交换),求最大高度。(n个矩形都要用到)
1,建图。当时第一步都没想到,鬼知道要长宽相连建图啊,但其实应该知道,这已经不是第一次遇到了。(第二次)
建图前想一想,该怎么建图,如果单纯相连,那图的意义,边的意义,点的意义是什么?
这里主要是边的意义,认为规定 a->b的有向边是这个矩形啊 a为宽,b为高放置。(鬼才想的到,我想不到。)
利用约束条件有对这个图产生了新的限制:一个点最多一个出度(这个点只能做一次宽)
这个图可能有许多连通分支,就挑一个来看,这个连通分支有什么特点
2,已知:输入保证n个矩形能叠起来
那上界,n个点是不是最多n条边? 额,不知道。
证明一下咯,如果有n+1条边,至少一个点的出度>=2.
有n条边,那连通分支中有一个环,再加一条边,又多一个环,就是说,n+1条边的无向图中有两个环
一个环已经自给自足了,没法有出度的边了,那只能别人进去,有两个别人需要进去的点(环缩点),那势必有一个点需要出度两次。
所以n个点的连通分支最多只有n条边。
考虑下界,n个点的连通分支最少有n-1条边(一棵树,真的不能再少了,再少就两个连通分支了。。。)
所以只有两种情况,n个点n条边,每个点都出度一次
n个点n-1条边,有一个点无需出(哪个点不用做宽啊,哪肯定是值最大的那个啊,给我滚去做高啊)
那怎么写啊。。。。。额
抄一波代码
Select Code
#include<bits/stdc++.h>
using namespace std;
#define clr(a, x) memset(a, x, sizeof(a))
#define mp(x, y) make_pair(x, y)
#define pb(x) push_back(x)
#define X first
#define Y second
#define fastin \
ios_base::sync_with_stdio(0); \
cin.tie(0);
typedef long long LL;
const int N = 5e5;
vector<int>G[N];
int val[N];
int vis[N];
int sz=0;int maxv,deg;
LL ans=0;
map<int,int> id;
void dfs(int u){
vis[u]=1;
deg+=G[u].size()-2; //妙啊 一条边贡献两个度数,要是树的话,只有2n-2个总度数
ans+=LL(val[u])*(G[u].size()-1);
maxv=max(maxv,val[u]); //维护最大点
for(auto v:G[u]){
if(!vis[v]) dfs(v);
}
}
int main(){
int n;cin>>n;
for(int i=0,x,y;i<n;i++){
cin>>x>>y;
if(id.find(x)==id.end()) id[x]=++sz,val[sz]=x; //缩点
if(id.find(y)==id.end()) id[y]=++sz,val[sz]=y;
G[id[x]].pb(id[y]);
G[id[y]].pb(id[x]);
}
clr(vis,0);
ans=0;
for(int i=1;i<=sz;i++){
if(!vis[i])
{
maxv=0,deg=0;
dfs(i);
if(deg!=0) ans+=maxv; //是个树加上最大的那个点
}
}
cout<<ans<<endl;
return 0;
}