标签:ems rem 最小 read cto string sizeof round team
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 153428/153428 K (Java/Others)
Total Submission(s): 1328 Accepted Submission(s): 435
这题O(n)做竟然卡读入优化。。。。。。。。。。。。。。。。。。。。。。用一般的读入优化竟然TLE。
从大佬哪里求得黑科技,样例输不进去竟然AC了:
namespace IO
{
const int U=40*1024*1024;
char buf[U];
int ptr,sz;
void begin()
{
ptr=0;
sz=fread(buf,1,U,stdin);
}
template<typename T>
inline bool scan_d (T&t)
{
while(ptr<sz&&buf[ptr]!=‘-‘&&(buf[ptr]<‘0‘||buf[ptr]>‘9‘)) ptr++;
if(ptr>=sz) return false;
bool sgn=false;
if(buf[ptr]==‘-‘) sgn=true,ptr++;
for(t=0;ptr<sz&&‘0‘<=buf[ptr]&&buf[ptr]<=‘9‘;ptr++)
t=t*10+buf[ptr]-‘0‘;
if(sgn) t=-t;
return true;
}
}
using namespace IO;
①很显然,如果我们最终的答案是一个包含K个点的整个联通块的话,显然答案就是K-1.如果我们是两个共包含K个点的联通块的话,显然答案会对应减少。
所以我们希望分部的情况是尽可能多的联通块,那么理应我们希望将结果分成若干个两两相连的小联通块。
②我们希望构成尽可能多的这样两两相连的小联通块(只用一条边去连接)的话,很显然是需要跑最大二分匹配数。我们知道最小点覆盖==最大二分匹配数,而直接建图跑二分图匈牙利匹配的话,时间复杂度很爆炸,我们知道树形dp可以O(n)求树上的最小点覆盖问题,所以我们直接跑树形Dp即可。
③如果我们最小点覆盖数为ans个,那么分情况讨论即可:
如果k<=ans*2,那么结果就是k/2
如果k>ans*2,那么结果就是k-ans*2+ans(多出来的点直接往上加即可)
如果k是奇数,那么答案再加1.
#include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 100010 using namespace std; int T,n,k,tot; int dp[MAXN][2]; vector<int>vec[MAXN]; namespace IO { const int U=40*1024*1024; char buf[U]; int ptr,sz; void begin() { ptr=0; sz=fread(buf,1,U,stdin); } template<typename T> inline bool scan_d (T&t) { while(ptr<sz&&buf[ptr]!=‘-‘&&(buf[ptr]<‘0‘||buf[ptr]>‘9‘)) ptr++; if(ptr>=sz) return false; bool sgn=false; if(buf[ptr]==‘-‘) sgn=true,ptr++; for(t=0;ptr<sz&&‘0‘<=buf[ptr]&&buf[ptr]<=‘9‘;ptr++) t=t*10+buf[ptr]-‘0‘; if(sgn) t=-t; return true; } } using namespace IO; void dfs(int fa,int now){ dp[now][0]=0; dp[now][1]=1; for(int i=0;i<vec[now].size();i++) if(vec[now][i]!=fa){ dfs(now,vec[now][i]); dp[now][0]+=dp[vec[now][i]][1]; dp[now][1]+=min(dp[vec[now][i]][0],dp[vec[now][i]][1]); } } int main(){ IO::begin(); scan_d(T); while(T--){ tot=0; memset(dp,0,sizeof(dp)); scan_d(n);scan_d(k); for(int i=1;i<=n;i++) vec[i].clear(); for(int i=1;i<n;i++){ int x; scan_d(x); vec[x].push_back(i+1); vec[i+1].push_back(x); } dfs(0,1); int ans=min(dp[1][0],dp[1][1]); if(ans*2>=k) printf("%d\n",(k+1)/2); if(ans*2<k) printf("%d\n",ans+k-2*ans); } }
标签:ems rem 最小 read cto string sizeof round team
原文地址:http://www.cnblogs.com/cangT-Tlan/p/7580113.html