您的位置:首页 > 其它

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)

【代码君】

//
//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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐