文章目录
写在前面
后来补上的blog
题解报告: By 林希
题解引用林希的题解报告,会以图片形式给出
Problem 1 食物中毒(medicine.pas/c/cpp)
分析
emm,直接暴力有80分。
看看那个异或操作,想一想位运算优化
代码
80分(不加位运算优化)
/***************************
User:Mandy.H.Y
Language:c++
Problem:medicine
Algorithm:DFS
Scors:80
***************************/
#include<bits/stdc++.h>
using namespace std;
const int maxn=25;
const int maxm=55;
int n,m;
bool ans[maxm],vis[maxn];
int med[maxn][maxm],cnt[maxm],ned[maxm],tot[maxm],a[maxn];
bool S[(1<<21)+5];
template<class T>inline void read(T &x){
x=0;bool flag=0;char ch=getchar();
while(!isdigit(ch)) flag|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(flag)x=-x;
}
template<class T>void putch(const T x){
if(x>9) putch(x/10);
putchar(x%10|48);
}
template<class T>void put(const T x){
if(x<0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("medicine10.in","r",stdin);
freopen("medicine.out","w",stdout);
}
bool dfs(int dep,int u){
int judge=1;
for(int i=1;i<=m;++i){
if(tot[ned[i]]%2==0){
judge=0;
break;
}
}
if(judge) return 1;
if(dep>n) return 0;
for(int i=u+1;i<=n;++i){
if(vis[i]) continue;
vis[i]=1;//其实可以不要 vis
for(int j=1;j<=med[i][0];++j){
++tot[med[i][j]];
if(ans[med[i][j]]&&tot[med[i][j]]==cnt[med[i][j]]&&(tot[med[i][j]]%2==0)) {
for(int k=1;k<=j;++k){
--tot[med[i][k]];//可以换成一伙
}
vis[i]=0;//要先撤回标记再return
//这件事提醒我们要边写边加注
return 0;
}
}
if(dfs(dep+1,i)) return 1;
vis[i]=0;
for(int j=1;j<=med[i][0];++j){
--tot[med[i][j]];
}
}
return 0;
}
void init(){
memset(ans,0,sizeof(ans));
memset(tot,0,sizeof(tot));
memset(vis,0,sizeof(vis));
memset(cnt,0,sizeof(cnt));
}
void readdata(){
for(int i=1;i<=m;++i){
int x;read(x);ned[i]=x;
ans[x]=1;
}
for(int i=1;i<=n;++i){
read(med[i][0]);
a[i]=i;
for(int j=1;j<=med[i][0];++j){
read(med[i][j]);
++cnt[med[i][j]];
}
}
}
void work(){
while(~scanf("%d%d",&n,&m)){
int judge=0;
init();
readdata();
for(int i=1;i<=m;++i){
if(cnt[ned[i]]==0) {
judge=1;
break;
}
}
if(judge){
printf("Impossible\n");
continue;
}
if(dfs(1,0)) printf("Possible\n");
else printf("Impossible\n");
}
}
int main(){
// int times=clock();
file();
work();
// printf("%.4llf",double(clock()-times)/CLOCKS_PER_SEC);
return 0;
}
100分
/***************************
User:Mandy.H.Y
Language:c++
Problem:medicine
Algorithm:DFS+位运算优化
Scors:100
***************************/
#include<bits/stdc++.h>
using namespace std;
const int maxn=25;
const int maxm=55;
int n,m;
long long S;
long long med[maxn];
template<class T>inline void read(T &x){
x=0;bool flag=0;char ch=getchar();
while(!isdigit(ch)) flag|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(flag)x=-x;
}
template<class T>void putch(const T x){
if(x>9) putch(x/10);
putchar(x%10|48);
}
template<class T>void put(const T x){
if(x<0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("medicine10.in","r",stdin);
freopen("medicine.out","w",stdout);
}
bool dfs(int dep,int u,long long s){
if((S&s)==S) return 1;
if(dep>n) return 0;
for(int i=u+1;i<=n;++i){
long long now=s;
now^=med[i];
if(dfs(dep+1,i,now)) return 1;
}
return 0;
}
void init(){
memset(med,0,sizeof(med));
}
void readdata(){
for(int i=1;i<=m;++i){
long long x;read(x);
S|=((long long)1<<x);
}
for(int i=1;i<=n;++i){
int x;
read(x);
for(int j=1;j<=x;++j){
long long y;
read(y);
med[i]^=((long long)1<<y);
}
}
}
void work(){
while(~scanf("%d%d",&n,&m)){
S=0;
init();
readdata();
if(dfs(1,0,0)) printf("Possible\n");
else printf("Impossible\n");
}
}
int main(){
// int times=clock();
// file();
work();
// printf("%.4llf",double(clock()-times)/CLOCKS_PER_SEC);
return 0;
}
Problem 2 消息传递(message.pas/c/cpp)
分析
最简单的一道,相当于tarjan的模板了
代码
/***************************
User:Mandy.H.Y
Language:c++
Problem:message
Algorithm:tarjan
***************************/
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int maxm=2e5+5;
int n,m,first[maxn],size=0,cnt=0,tp=0;
int dfn[maxn],low[maxn];
bool vis[maxn],ans[maxn];
int st[maxn];
struct Edge{
int v,nt;
}edge[maxm];
template<class T>inline void read(T &x){
x=0;bool flag=0;char ch=getchar();
while(!isdigit(ch)) flag|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(flag)x=-x;
}
template<class T>void putch(const T x){
if(x>9) putch(x/10);
putchar(x%10|48);
}
template<class T>void put(const T x){
if(x<0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("message.in","r",stdin);
freopen("message.out","w",stdout);
}
void eadd(int u,int v){
edge[++size].v=v;
edge[size].nt=first[u];
first[u]=size;
}
void readdata(){
read(n);read(m);
for(int i=1;i<=m;++i){
int u,v;read(u);read(v);
eadd(u,v);
}
}
void tarjan(int u){
dfn[u]=low[u]=++cnt;
st[tp++]=u;
vis[u]=1;
for(int i=first[u];i;i=edge[i].nt){
int v=edge[i].v;
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}else if(vis[v]) low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
int now,judge=0;
if(st[tp-1]!=u) judge=1;
do{
now=st[tp-1];
--tp;
vis[now]=0;
if(judge) ans[now]=1;
}while(now!=u);
}
}
void work(){
// int times=clock();
for(int i=1;i<=n;++i)
if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;++i){
if(ans[i]) printf("T\n");
else printf("F\n");
}
// printf("%.4llf",double(clock()-times)/CLOCKS_PER_SEC);
}
int main(){
// file();
readdata();
work();
return 0;
}
Problem 3 周年纪念日(anniversary.pas/c/cpp)
分析
最小瓶颈路 + 树形DP
代码
prim:
/*****************************
User:Mandy.H.Y
Language:c++
Problem:
Algorithm:Prim
*****************************/
//日常证明:虽然是一个很简单的结论,很容易就想到了
//求最小花费:最小生成树
//看最小生成树原理:
//prim贪点,类似Dijkstra,松弛原理
//kruskal贪边,先排序,再用并查集合并
//最小生成树保证了最大边最小
//证明:
//如果有一种方案满足最大边小于最小生成树,
//且总边权大于最小生成树,记这颗生成树为 A
//我们从最小生成树得到这颗生成树
//先断边:把最小生成树中大于A的最大边的边断掉
//这一步必会把 A 中最大边所连的两点断开
//如果没有被断掉,说明最大值不是这一个,因为两点间有更小的最大值
//再连边,连上最大边,把剩下的点用小于最大边的边连上
//注意:因为刚刚断掉的边都是大于最大边的, 现在所连的边都小于等于最大边,边权之和更小
//而刚刚的被断的是最小生成树,矛盾
//所以 最小生成树保证了最大边最小
//BY Mandy.H.Y 20190525
//PS.对于第2个问,有没有很像 伟大的奶牛聚集Great cow gathering?
//详见luogu2986
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int maxm=2e5+5;
typedef long long LL;
typedef pair<long long,long long> pir;
priority_queue<pir,vector<pir>,greater<pir> >q;
LL n,m,size,totcost,maxw,size1,totp,id,happy;
LL first1[maxn],first[maxn],p[maxn],dis[maxn],father[maxn];
LL cnt[maxn],f[maxn];
bool vis[maxn];
struct Edge{
LL v,nt,w;
}edge[maxm<<1],edge1[maxn<<1];
template<class T>inline void read(T &x){
x=0;bool flag=0;char ch=getchar();
while(!isdigit(ch)) flag|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(flag)x=-x;
}
template<class T>void putch(const T x){
if(x>9) putch(x/10);
putchar(x%10|48);
}
template<class T>void put(const T x){
if(x<0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("1.txt","r",stdin);
}
void eadd(LL u,LL v,LL w){
edge[++size].v=v;
edge[size].w=w;
edge[size].nt=first[u];
first[u]=size;
}
void eadd1(LL u,LL v,LL w){
edge1[++size1].v=v;
edge1[size1].w=w;
edge1[size1].nt=first1[u];
first1[u]=size1;
}
void readdata(){
read(n);read(m);
for(int i=1;i<=n;++i) read(p[i]),totp+=p[i];
for(int i=1;i<=m;++i){
long long u,v,w;
read(u);read(v);read(w);
eadd(u,v,w);eadd(v,u,w);
}
}
void prim(){
for(int i=2;i<=n;++i) dis[i]=2e15;
q.push(make_pair((LL)0,(LL)1));
while(!q.empty()){
LL u=q.top().second;q.pop();
if(vis[u]) continue;
totcost+=dis[u];
eadd1(father[u],u,dis[u]);
vis[u]=1;
maxw=max(maxw,dis[u]);
for(int i=first[u];i;i=edge[i].nt){
LL v=edge[i].v,w=edge[i].w;
if(w<dis[v]){
dis[v]=w;
father[v]=u;
q.push(make_pair(dis[v],v));
}
}
}
}
void dfs1(LL u){
for(int i=first1[u];i;i=edge1[i].nt){
LL v=edge1[i].v,w=edge1[i].w;
dis[v]=dis[u]+w;
dfs1(v);
p[u]+=p[v];
f[u]+=f[v]+p[v]*w;//先算出子树中的代价
}
}
void dfs2(LL u){
for(int i=first1[u];i;i=edge1[i].nt){
LL v=edge1[i].v,w=edge1[i].w;
f[v]=f[u]-p[v]*w+(totp-p[v])*w;
//子节点为根的代价 =节点子树的代价 + (父节点为根的代价 - 子节点子树的代价 - 子节点的子树的居民从子节点转移到父节点的代价)+ 剩余节点从父节点 转移到子节点的代价
// == 父节点为根的代价 - 子节点的子树的居民从子节点转移到父节点的代价+ 剩余节点从父节点 转移到子节点的代价
//()里面等于剩余节点到父节点的代价
if(f[v]<happy){
happy=f[v];id=v;
}
dfs2(v);
}
}
void work(){
prim();
put(totcost);putchar(' ');
put(maxw);putchar('\n');
dfs1(1);
happy=f[1];id=1;
dfs2(1);
put(id);putchar(' ');
put(happy);putchar('\n');
}
int main(){
// file();
readdata();
work();
return 0;
}
kruskal
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 100005;
struct edge
{
int to,nxt,wgt;
} info[MAXN << 1];
struct node
{
int from,to,wgt;
friend bool operator <(const node &na,const node &nb)
{
return na.wgt < nb.wgt;
}
} Edge[MAXN << 1];
int n,m,e,ui,vi,wi,cost,maxd,minID = INT_MAX;
long long mind = LLONG_MAX;
int head[MAXN],ufs[MAXN],sumPopulation[MAXN],population[MAXN];
long long dist[MAXN];
template<typename T> void qread(T &sum)
{
sum = 0;
register char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9')
{
sum = (sum << 1) + (sum << 3) + ch - '0';
ch = getchar();
}
}
template<typename T> void qwrite(const T x)
{
if (x < 0)
{
putchar('-');
qwrite(-x);
}
else
{
if (x >= 10) qwrite(x / 10);
putchar(x % 10 + '0');
}
}
inline void addedge(int from,int to,int wgt)
{
info[++e].to = to;
info[e].wgt = wgt;
info[e].nxt = head[from];
head[from] = e;
}
inline int find(int u)
{
return ufs[u] == u ? u : ufs[u] = find(ufs[u]);
}
void preDfs(int u,int f)
{
for (int i = head[u]; i; i = info[i].nxt)
{
int v = info[i].to;
if (v == f) continue;
preDfs(v,u);
sumPopulation[u] += sumPopulation[v];
dist[u] += dist[v] + sumPopulation[v] * info[i].wgt;
}
}
void postDfs(int u,int f)
{
for (int i = head[u]; i; i = info[i].nxt)
{
int v = info[i].to;
if (v == f) continue;
dist[v] += dist[u] - sumPopulation[v] * info[i].wgt + (sumPopulation[1] - sumPopulation[v]) * info[i].wgt;
postDfs(v,u);
}
}
void init()
{
// freopen("anniversaryIN.txt","r",stdin);
// freopen("anniversaryOUT.txt","w",stdout);
scanf("%lld%lld",&n,&m);
for (int i = 1; i <= n; ++i) ufs[i] = i;
for (int i = 1; i <= n; ++i)
{
qread(population[i]);
sumPopulation[i] = population[i];
}
for (int i = 1; i <= m; ++i)
{
qread(Edge[i].from);
qread(Edge[i].to);
qread(Edge[i].wgt);
}
sort(Edge + 1,Edge + m + 1);
}
void work()
{
int used = 0;
for (int i = 1; i <= m; ++i)
{
if (used == n - 1) break;
int u = find(Edge[i].from);
int v = find(Edge[i].to);
if (u != v)
{
ufs[u] = v;
cost += Edge[i].wgt;
maxd = max(maxd,Edge[i].wgt);
addedge(Edge[i].from,Edge[i].to,Edge[i].wgt);
addedge(Edge[i].to,Edge[i].from,Edge[i].wgt);
used++;
}
}
preDfs(1,0);
for (int i = 2;i <= n;++i) dist[i] = 0;
postDfs(1,0);
for (int i = 1; i <= n; ++i)
{
if (mind > dist[i])
{
minID = i;
mind = dist[i];
}
}
printf("%lld %lld\n%lld %lld",cost,maxd,minID,mind);
}
#undef int
int main()
{
init();
work();
return 0;
}