2016CCPC东北地区大学生程序设计竞赛 - 重现赛 部分题解
2016-10-08 16:27
309 查看
【题目链接】http://acm.hdu.edu.cn/search.php?field=problem&key=2016CCPC%B6%AB%B1%B1%B5%D8%C7%F8%B4%F3%D1%A7%C9%FA%B3%CC%D0%F2%C9%E8%BC%C6%BE%BA%C8%FC+-+%D6%D8%CF%D6%C8%FC&source=1&searchmode=source
【1001】 简单想下kruskal的过程就可以发现答案是(n-1)*(n+2)/2;
【1003】
DC+CD=1t+t
DC=t≥1 时,答案递增
A≤C,D≤B ,t=BA 时,答案最大
【1004】离散化后 BFS。
//
//Created by just_sort 2016/9/12 16:50
//Copyright (c) 2016 just_sort.All Rights Reserved
//
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 100010;
const int maxm = 1000;
const int dir[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
int vis[maxm][maxm];
struct node{
int x,y;
node(){}
node(int x,int y):x(x),y(y){}
}p[maxm];
int K, N, M, n, m;
int tx[maxn], ty[maxn], d[maxn];
LL vx[maxn], vy[maxn];
vector <LL> res;
bool check(int x, int y)
{
if(x >= 1 && x <= n && y >= 1 && y <= m) return true;
else return false;
}
void init(){
res.clear();
memset(d,0,sizeof(0));
memset(vis,0,sizeof(vis));
N = M = 0;
}
int lishanhua(int *x, LL *vx, int &w, bool flag)
{
sort(x, x+w);
w = unique(x, x + w) - x;
int t = 1;
d[0] = x[0];
for(int i = 1; i < w; i++){
if(x[i] != x[i-1] + 1) d[t++] = x[i-1] + 1;
d[t++] = x[i];
}
sort(d, d+t);
for(int i = 1; i < t; i++){
vx[i] = d[i] - d[i-1];
}
for(int i = 0; i < K; i++){
if(flag) p[i].x = lower_bound(d, d + t, p[i].x) - d;
else p[i].y = lower_bound(d, d + t, p[i].y) - d;
}
return t - 1;
}
LL bfs(int x, int y)
{
queue<node>q;q.push(node(x,y));vis[x][y] = 1;LL ans = vx[x]*vy[y];
while(q.size()){
node now = q.front(); q.pop();
for(int i = 0; i < 4; i++){
int dx = now.x + dir[i][0]; int dy = now.y + dir[i][1];
if(vis[dx][dy] || !check(dx,dy)) continue;
vis[dx][dy] = 1; ans = ans + vx[dx]*vy[dy];q.push(node(dx,dy));
}
}
return ans;
}
int main()
{
int T, ks = 1;
scanf("%d",&T);
while(T--)
{
init();
scanf("%d%d%d",&n,&m,&K);
tx[N++] = 0, tx[N++] = n, ty[M++] = 0, ty[M++] = m;
for(int i = 0; i < K; i++){
scanf("%d%d",&p[i].x,&p[i].y);
tx[N++] = p[i].x - 1, tx[N++] = p[i].x;
ty[M++] = p[i].y - 1, ty[M++] = p[i].y;
}
n = lishanhua(tx, vx, N, 1); m = lishanhua(ty, vy, M, 0);
for(int i = 0; i < K; i++){
vis[p[i].x][p[i].y] = 1;
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(!vis[i][j]) res.push_back(bfs(i,j));
}
}
sort(res.begin(),res.end());
printf("Case #%d:\n",ks++);
printf("%d\n",(int) res.size());
for(int i = 0; i < res.size(); i++){
if(i) printf(" ");
printf("%I64d",res[i]);
}
printf("\n");
}
return 0;
}
【1006】模拟一下连连看的可以消除的条件。
【1007】一个被删除的点能否被复原取决于这个点是否存在两个不全为空的子树。 ,所以读入以后dfs一次求出每个点有多少子树 ,然后对于每次询问,只需要建出删除那些点的树,递归的计算每个点有多少子树不全为空。
【复杂度】O(n*q)
【代码君】
【1009】
【解题方法】数据结构模拟题,用deque就可以了。关键是要发现这个式子的规律,把O(n)的计算变成O(1)。以下解题报告摘自:http://blog.csdn.net/kevin66654/article/details/52753144
1:0和任何数与非得到1(这个任何数不仅仅指0,1,也指任意一个01序列)
2:奇数个1与非得到1,偶数个1与非得到0
那么,我们可以知道:我们需要统计的是连续的0和1的个数(用pair(x,y)来放入deque中)
x代表0或者1,y代表当前的x连续有多少个
那么,如何来计算呢?
特殊情况:deque中就一个元素:根据规律算一下
否则:
我们需要判断一下:如果首元素是0,那么答案是1(0和任何数与非得到1)
如果首元素是1,那么我们就知道,第二个元素肯定是0
如果连续的0只有1个而且deque中只有两个元素那么这个0元素是个特殊情况
否则:
因为0与任何数与非得到1
相当于首元素是1的连续个数长了一个,用O(1)的复杂度就可以AC了。
【复杂度】O(n)。
【代码君】
【1001】 简单想下kruskal的过程就可以发现答案是(n-1)*(n+2)/2;
【1003】
DC+CD=1t+t
DC=t≥1 时,答案递增
A≤C,D≤B ,t=BA 时,答案最大
【1004】离散化后 BFS。
//
//Created by just_sort 2016/9/12 16:50
//Copyright (c) 2016 just_sort.All Rights Reserved
//
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 100010;
const int maxm = 1000;
const int dir[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
int vis[maxm][maxm];
struct node{
int x,y;
node(){}
node(int x,int y):x(x),y(y){}
}p[maxm];
int K, N, M, n, m;
int tx[maxn], ty[maxn], d[maxn];
LL vx[maxn], vy[maxn];
vector <LL> res;
bool check(int x, int y)
{
if(x >= 1 && x <= n && y >= 1 && y <= m) return true;
else return false;
}
void init(){
res.clear();
memset(d,0,sizeof(0));
memset(vis,0,sizeof(vis));
N = M = 0;
}
int lishanhua(int *x, LL *vx, int &w, bool flag)
{
sort(x, x+w);
w = unique(x, x + w) - x;
int t = 1;
d[0] = x[0];
for(int i = 1; i < w; i++){
if(x[i] != x[i-1] + 1) d[t++] = x[i-1] + 1;
d[t++] = x[i];
}
sort(d, d+t);
for(int i = 1; i < t; i++){
vx[i] = d[i] - d[i-1];
}
for(int i = 0; i < K; i++){
if(flag) p[i].x = lower_bound(d, d + t, p[i].x) - d;
else p[i].y = lower_bound(d, d + t, p[i].y) - d;
}
return t - 1;
}
LL bfs(int x, int y)
{
queue<node>q;q.push(node(x,y));vis[x][y] = 1;LL ans = vx[x]*vy[y];
while(q.size()){
node now = q.front(); q.pop();
for(int i = 0; i < 4; i++){
int dx = now.x + dir[i][0]; int dy = now.y + dir[i][1];
if(vis[dx][dy] || !check(dx,dy)) continue;
vis[dx][dy] = 1; ans = ans + vx[dx]*vy[dy];q.push(node(dx,dy));
}
}
return ans;
}
int main()
{
int T, ks = 1;
scanf("%d",&T);
while(T--)
{
init();
scanf("%d%d%d",&n,&m,&K);
tx[N++] = 0, tx[N++] = n, ty[M++] = 0, ty[M++] = m;
for(int i = 0; i < K; i++){
scanf("%d%d",&p[i].x,&p[i].y);
tx[N++] = p[i].x - 1, tx[N++] = p[i].x;
ty[M++] = p[i].y - 1, ty[M++] = p[i].y;
}
n = lishanhua(tx, vx, N, 1); m = lishanhua(ty, vy, M, 0);
for(int i = 0; i < K; i++){
vis[p[i].x][p[i].y] = 1;
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(!vis[i][j]) res.push_back(bfs(i,j));
}
}
sort(res.begin(),res.end());
printf("Case #%d:\n",ks++);
printf("%d\n",(int) res.size());
for(int i = 0; i < res.size(); i++){
if(i) printf(" ");
printf("%I64d",res[i]);
}
printf("\n");
}
return 0;
}
【1006】模拟一下连连看的可以消除的条件。
【1007】一个被删除的点能否被复原取决于这个点是否存在两个不全为空的子树。 ,所以读入以后dfs一次求出每个点有多少子树 ,然后对于每次询问,只需要建出删除那些点的树,递归的计算每个点有多少子树不全为空。
【复杂度】O(n*q)
【代码君】
// //Created by just_sort 2016/10/5 //Copyright (c) 2016 just_sort.All Rights Reserved // #include <set> #include <map> #include <queue> #include <stack> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; const int maxn = 111111; vector<int>g[maxn]; int edgecnt,head[maxn]; struct EDGE{ int to,next; }E[maxn*2]; void init(){ edgecnt = 0; memset(head,-1,sizeof(head)); } void addedge(int u,int v){ E[edgecnt].to = v,E[edgecnt].next = head[u],head[u] = edgecnt++; } int sz[maxn],fa[maxn],d[maxn],a[maxn]; void dfs(int u,int father) { sz[u] = 0; fa[u] = father; for(int i = head[u]; ~i; i = E[i].next) { int v = E[i].to; if(v == father) continue; dfs(v,u); sz[u]++; } } int check(int u) { if(d[u] != -1) return d[u]; int suv = 0,son = 0; for(int i = 0; i < g[u].size(); i++) { if(check(g[u][i])) suv++; son++; } return d[u] = sz[u] - son + suv; } int main() { int T,ks = 1; int n,q; scanf("%d",&T); while(T--) { init(); scanf("%d%d",&n,&q); for(int i = 1; i < n; i++){ int u,v; scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } dfs(1,0); printf("Case #%d:\n",ks++); for(int i = 1; i <= q; i++) { int m; scanf("%d",&m); for(int i = 1; i <= m; i++) { scanf("%d",&a[i]); g[a[i]].clear(); d[a[i]] = -1; } for(int i = 1; i <= m; i++) { if(d[fa[a[i]]] == -1) g[fa[a[i]]].push_back(a[i]); } int ans = n - m; for(int i = 1; i <= m; i++) { if(check(a[i]) >= 2) ans++; } printf("%d\n",ans); } } return 0; }
【1009】
【解题方法】数据结构模拟题,用deque就可以了。关键是要发现这个式子的规律,把O(n)的计算变成O(1)。以下解题报告摘自:http://blog.csdn.net/kevin66654/article/details/52753144
1:0和任何数与非得到1(这个任何数不仅仅指0,1,也指任意一个01序列)
2:奇数个1与非得到1,偶数个1与非得到0
那么,我们可以知道:我们需要统计的是连续的0和1的个数(用pair(x,y)来放入deque中)
x代表0或者1,y代表当前的x连续有多少个
那么,如何来计算呢?
特殊情况:deque中就一个元素:根据规律算一下
否则:
我们需要判断一下:如果首元素是0,那么答案是1(0和任何数与非得到1)
如果首元素是1,那么我们就知道,第二个元素肯定是0
如果连续的0只有1个而且deque中只有两个元素那么这个0元素是个特殊情况
否则:
因为0与任何数与非得到1
相当于首元素是1的连续个数长了一个,用O(1)的复杂度就可以AC了。
【复杂度】O(n)。
【代码君】
// //Created by just_sort 2016/10/8 //Copyright (c) 2016 just_sort.All Rights Reserved // #include <set> #include <map> #include <queue> #include <stack> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; pair<int,int>p; deque<pair<int,int> >q; deque<pair<int,int> >::iterator it; deque<pair<int,int> >::reverse_iterator rit; int main() { int T,ks = 1; scanf("%d",&T); while(T--) { printf("Case #%d:\n",ks++); while(!q.empty()) q.pop_back(); int n,x,ans; bool offset = true; char op[10]; scanf("%d",&n); for(int i = 1; i <= n; i++) { scanf("%s",op); if(strcmp(op,"PUSH") == 0) { scanf("%d",&x); if(q.size() == 0){ q.push_back(make_pair(x,1)); } else{ if(offset) { p = q.back(); q.pop_back(); if(p.first == x) { p.second++; q.push_back(p); } else { q.push_back(p); q.push_back(make_pair(x,1)); } } else { p = q.front(); q.pop_front(); if(p.first == x) { p.second++; q.push_front(p); } else { q.push_front(p); q.push_front(make_pair(x,1)); } } } } else if(strcmp(op,"POP") == 0) { if(offset) { p = q.back(); q.pop_back(); p.second--; if(p.second > 0) q.push_back(p); } else { p = q.front(); q.pop_front(); p.second--; if(p.second > 0) q.push_front(p); } } else if(strcmp(op,"REVERSE") == 0) { offset = !offset; } else { if(q.size() == 0) { printf("Invalid.\n"); } else { if(q.size() == 1) { p = q.front(); if(p.first == 0) { if(p.second == 1) ans = 0; else ans = 1; } else { if(p.second%2 == 1) ans = 1; else ans = 0; } } else { if(offset) { p = q.front(); if(p.first == 0) ans = 1; else { it = q.begin(); it++; p = *it; if(p.second == 1 && q.size() == 2) { if(q.front().second % 2 == 1) ans = 1; else ans = 0; } else { if(q.front().second % 2 == 1) ans = 0; else ans = 1; } } } else{ p = q.back(); if(p.first == 0) ans = 1; else { rit = q.rbegin(); rit--; p = *rit; if(p.second == 1 && q.size() == 2) { if(q.back().second%2 == 1) ans = 1; else ans = 0; } else { if(q.back().second % 2 == 1) ans = 0; else ans = 1; } } } } printf("%d\n",ans); } } } } return 0; }
相关文章推荐
- 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 A - Minimum’s Revenge HDU 5922
- HDU 5922 Minimum’s Revenge(思维题)——2016CCPC东北地区大学生程序设计竞赛 - 重现赛
- HDU 5926 Mr. Frog’s Game(连连看,暴力)——2016CCPC东北地区大学生程序设计竞赛 - 重现赛
- HDU 5929 Basic Data Structure(模拟,deque)——2016CCPC东北地区大学生程序设计竞赛 - 重现赛
- HDU 5924 Mr. Frog’s Problem(想看证明的来)——2016CCPC东北地区大学生程序设计竞赛 - 重现赛
- 【HDU5927 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 F】【dfs序 + 线段树 or 树状数组 复杂度计算】Auxiliary Set 一个点如果是好点或是两个好点的LCA就是好
- (HDU 5926)Mr. Frog’s Game 水题 <2016CCPC东北地区大学生程序设计竞赛 - 重现赛 >
- (HDU 5927)Auxiliary Set 思维题 <2016CCPC东北地区大学生程序设计竞赛 - 重现赛 >
- 【HDU5928 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 G】【计算几何 凸包思想 枚举底点做DP】Birthday Gift 给定绳长最多围住多少个点
- 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 D Coconuts HDU 5925
- (HDU 5929)Basic Data Structure 双端队列+模拟 <2016CCPC东北地区大学生程序设计竞赛 - 重现赛 >
- 【HDU5930 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 I】【线段树 预处理加变更贡献】GCD 动态修改维护全局gcd数量
- 【HDU5929 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 H】【打表找规律 队列模拟】Basic Data Structure 双端栈下连续1和0做nand的结果
- HDU Mr. Frog’s Problem 2016CCPC东北地区大学生程序设计竞赛 - 重现赛
- 【HDU5931 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 J】【线性规划 乱搞】Mission Possible 购买护甲和回复力和速度使得最小成本穿越D距离
- hdu 5927 Auxiliary Set 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 F题(树状dp)
- 【HDU5932 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 K】【树上背包 贪心乱搞】Backpack on Tree 物品成本只有12345下的树上背包
- 2016CCPC东北地区大学生程序设计竞赛 Auxiliary Set (BFSt预处理+ 思维)
- HDU Mr. Frog’s Game 2016CCPC东北地区大学生程序设计竞赛 - 重现赛
- HDU Basic Data Structure 2016CCPC东北地区大学生程序设计竞赛 - 重现赛