B:
题目大意:
给你N个盒子,第一个盒子一开始装着骨头,现在有m个位子上有漏洞,如果带有骨头的盒子移动到了这些位子上,那么骨头就会掉在漏洞上再也不会动。
问最终骨头在哪里、
每一次操作交换两个位子上的盒子。
自己的代码被hack了..其实只要动当前为ans的就可以了
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int vis[1000050];
int a[1000050];
int main()
{
int n,m,k;
while(~scanf("%d%d%d",&n,&m,&k))
{
memset(vis,0,sizeof(vis));
for(int i=0;i<m;i++)
{
int x;
scanf("%d",&x);
vis[x]=1;
}
int ans=1;
while(k--)
{
int x,y;
scanf("%d%d",&x,&y);
if(x==ans)
{
if(vis[x]!=1)ans=y;
}
else if(y==ans)
{
if(vis[y]!=1)ans=x;
}
}
printf("%d\n",ans);
}
}
C:
题目链接:http://codeforces.com/contest/796/problem/C
题目的意思是有n个点,n-1条边,现在让你任选一个点当做起点,去掉这个点,然后和这个点连接的所有的点的权值都加一,然后所有和那个点相连的点的点的点权也要加一,有点绕,慢慢理解,1->2->3,就是说去掉1后2和3的点权都要加一,然后问你最大集合中的最小点权。
心得:想法其实差不多,但是我wa了..
我打算dfs随便一个mx来比较与cmx ,mx 的距离.但其实这样是不可以的;
比如下面的话应该从2开始走的,
(所以正确的做法应该是按照题解一样,mx 的相邻的节点都应该是mx或者是cmx.)
自己wa的数据
Input
3
2 2 2
3 2
1 2
Participant’s output
4
Jury’s answer
3
参考http://blog.youkuaiyun.com/bless924295/article/details/70244270
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#define inf 0x3f3f3f3f
using namespace std;
int a[400000];
vector<int >G[400000];
int n;
int solve(){
int x=0,y=0;
int maxval=-inf;
for(int i=1;i<=n;i++){
if(a[i]>maxval)
maxval=a[i];
}
for(int i=1;i<=n;i++){
if(a[i]==maxval)
x++;
if(a[i]==maxval-1)
y++;
}
int xx=x;
int yy=y;
bool flag1=true;
bool flag2=true;
for(int i=1;i<=n;i++){
bool flag3=true;
if(a[i]==maxval)
x--;
else if(a[i]==maxval-1)
y--;
for(int j=0;j<(int )G[i].size();j++){
if(a[G[i][j]]==maxval){
x--;
flag3=false;
}
if(a[G[i][j]]==maxval-1)
y--;
}
if(x==0){
flag1=false;
if(y==0&&flag3)
flag2=false;
}
x=xx,y=yy;
}
if(!flag1){
if(flag2==0)
return maxval;
else
return maxval+1;
}
return maxval+2;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=0;i<n-1;i++){
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
int ans=solve();
cout<<ans<<endl;
return 0;
}
D:
参考http://blog.youkuaiyun.com/mengxiang000000/article/details/70146788
题目大意:
给你一个树,其中有N个点,N-1条无向边,现在有M个特殊点,问你最多可以切割多少条边,使得每个普通点到最近的特殊点的距离小于等于d.
保证有解。
体悟:一开始以为是树dp,结果怎么想都想不出来..
原来就只是个多点bfs而已…
贪心地使得每个点都被遇见一次…因为是树,如果第二次遇到,那么这条边是不用的,
#include<stdio.h>
#include<string.h>
#include<queue>
#include<vector>
using namespace std;
struct node
{
int to,pos;
}now,nex;
vector<node >mp[300800];
int vis[300800];
int ans[300800];
int main()
{
int n,m,k;
while(~scanf("%d%d%d",&n,&m,&k))
{
queue<int >s;
memset(vis,0,sizeof(vis));
memset(ans,0,sizeof(ans));
for(int i=1;i<=n;i++)mp[i].clear();
for(int i=0;i<m;i++)
{
int x;
scanf("%d",&x);
s.push(x);
vis[x]=1;
}
for(int i=1;i<=n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
now.to=y;
now.pos=i;
mp[x].push_back(now);
now.to=x;
now.pos=i;
mp[y].push_back(now);
}
while(!s.empty())
{
int u=s.front();
s.pop();
for(int i=0;i<mp[u].size();i++)
{
int v=mp[u][i].to;
if(vis[v]==0)
{
ans[mp[u][i].pos]=1;
vis[v]=1;
s.push(v);
}
}
}
int cnt=0;
for(int i=1;i<=n-1;i++)if(ans[i]==0)cnt++;
printf("%d\n",cnt);
for(int i=1;i<=n-1;i++)
{
if(ans[i]==0)printf("%d ",i);
}
printf("\n");
}
}
E:待补:http://codeforces.com/contest/796/problem/E dp
..
解题报告:
考虑用f[i][j][x][y]
表示考虑完前i个问题,当前总共用了j次机会,对于第一个人还能看x道题,第二个人还能看y道题的最优值,考虑x和y等于0
的情况,直接转移就好了。
这里写转出可能会方便一些。
注意到这个复杂度是O(npk2)
的,但是当p>2∗nk时,可以全选,那么直接全选就好了,特判一下,所以复杂度是O(n2k)。
心得:这个地方还是挺难想到这个状态的。。
要记录左边,右边还可以看多少次。。看了多少次,看到第几题。。。这样的话满足了dp 的要求。。
别人的代码:
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
int f[2][1005][55][55];
int a[1005],b[1005];
int main()
{
int n,p,k;
scanf("%d%d%d",&n,&p,&k);
if(p>2*(n+k-1)/k)
p=2*(n+k-1)/k;
int n1,n2,x;
scanf("%d",&n1);
int i,j;
for(i=1;i<=n1;i++)
{
scanf("%d",&x);
a[x]=1;
}
scanf("%d",&n2);
for(i=1;i<=n2;i++)
{
scanf("%d",&x);
b[x]=1;
}
int y;
memset(f,-127/3,sizeof(f));
f[0][0][0][0]=0;
int p1=1,p2=0;
for(i=1;i<=n;i++)
{
for(j=0;j<=p;j++)
{
for(x=0;x<k;x++)
{
for(y=0;y<k;y++)
{
if(y!=0)
f[p1][j+1][k-1][y-1]=max(f[p1][j+1][k-1][y-1],f[p2][j][x][y]+(a[i]||b[i]));
else
f[p1][j+1][k-1][0]=max(f[p1][j+1][k-1][0],f[p2][j][x][y]+a[i]);
if(x!=0)
f[p1][j+1][x-1][k-1]=max(f[p1][j+1][x-1][k-1],f[p2][j][x][y]+(a[i]||b[i]));
else
f[p1][j+1][0][k-1]=max(f[p1][j+1][0][k-1],f[p2][j][x][y]+b[i]);
if(x!=0&&y!=0)
f[p1][j][x-1][y-1]=max(f[p1][j][x-1][y-1],f[p2][j][x][y]+(a[i]||b[i]));
else if(x!=0)
f[p1][j][x-1][0]=max(f[p1][j][x-1][0],f[p2][j][x][y]+a[i]);
else if(y!=0)
f[p1][j][0][y-1]=max(f[p1][j][0][y-1],f[p2][j][x][y]+b[i]);
else
f[p1][j][0][0]=max(f[p1][j][0][0],f[p2][j][x][y]);
}
}
}
p1=1-p1;
p2=1-p2;
for(j=0;j<=p;j++)
for(x=0;x<k;x++)
for(y=0;y<k;y++)
f[p1][j][x][y]=-100000;
}
int ans=0;
for(j=0;j<=p;j++)
for(x=0;x<k;x++)
for(y=0;y<k;y++)
ans=max(ans,f[p2][j][x][y]);
printf("%d\n",ans);
return 0;
}
本文解析了Codeforces 796比赛中的五道题目,包括A至E题的算法思路与实现细节,涵盖图论、树形结构、动态规划等核心概念。
842

被折叠的 条评论
为什么被折叠?



