[考试总结]noip模拟54
因为昨天晚上上了一个厕所,所以被叫到年级部与体育老师理论,然后要停我的课。
\[toilet==class?!!!
\]
然后今天还好被教练英勇救出,不然就要被体育老师。。。。
选择
一个小小的状压。
首先,每个子树内,最多有一条路径往子树上面延伸,所以我们记录一个 \(link_{i,j}\) 表示同一个父亲 \(x\) 的儿子们是否可以作出贡献。
假设当前在结点 \(x\),那么现在 \(x\) 子树的答案就是所有儿子的答案加上子树 \(x\) 内跨过 \(x\) 的路径的答案。
然后就用状压来处理这个最大匹配问题
然后就没了。。
%: pragma GCC optimize("Ofast,O3,inline")
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(a) FILE *FI = freopen(#a".in","r",stdin); FI = freopen(#a".out","w",stdout)
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define debug cout<<"debug"<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
#define qk(x,size) memset(x,0,size)
char buf[1<<20],*p1 = buf,*p2 = buf; int ak; typedef long long ll; typedef unsigned long long ull;
class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &s)
{
register int f = 0;s = 0; register char ch = gc();
while(!isdigit(ch)) {f |= ch == '-'; ch = gc();}
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io;static const int maxn = 1e6+10,two = 2e3+10,inf = 1e9+7;const ll llinf = 1e18+7;
auto max = [](int x,int y) -> int{return x > y ? x : y;}; auto min = [](int x,int y) -> int{return x < y ? x : y;};
namespace xin
{
int n,m,cnt;
class xin_edge{public:int next,ver;}edge[maxn];
int head[maxn],rp;
auto add = [](int x,int y) -> void{edge[++rp].ver = y; edge[rp].next = head[x]; head[x] = rp;};
bool vis[two][two];
std::vector < int > ok[two];
int ans[maxn];
auto merge = [](int x,int y) -> void
{
if(ok[x].size() < ok[y].size()) std::swap(ok[x],ok[y]);
for(int v : ok[y]) ok[x].push_back(v);
};
void dfs(int x,int fa)
{
int son[11],link[11][11],linx[11],f[(1 << 10) + 1],cnt = 0;
bool ji[11];
qk(son,sizeof(son)); qk(ji,sizeof(ji));
qk(link,sizeof(link)); qk(linx,sizeof(linx)); qk(f,sizeof(f));
ok[x].push_back(x);
go(i,x) if(y xor fa)
{
dfs(y,x);
son[cnt] = y; ++cnt;
}
try(i,0,cnt-1)
{
try(j,i+1,cnt-1)
for(int xx : ok[son[i]])
{
for(int yy : ok[son[j]])
if(link[i][j] or vis[xx][yy]) {link[i][j] = link[j][i] = 1; break;}
if(link[i][j]) break;
}
for(int xx : ok[son[i]]) { if(vis[xx][x]) {linx[i] = 1; break;}}
}
// try(i,0,cnt-1) try(j,0,cnt-1) if(link[i][j]) cout<<i<<' '<<j<<endl;
// try(i,0,cnt-1) if(linx[i]) cout<<"i = "<<i<<endl;
int ms = 1 << cnt; //jb(cnt);
try(s,0,ms-1)
{
try(i,0,cnt-1)
if(s & (1 << i))
{
if(linx[i]) f[s] = max(f[s],f[s xor (1 << i)] + 1);
try(j,i+1,cnt-1)
if(s & (1 << j))
if(link[i][j]) f[s] = max(f[s],f[s xor ((1 << i) | (1 << j))] + 1);
}
ans[x] = max(ans[x],f[s]);
// sb(s); jb(f[s]);
// jb(ans[x]);
}
try(s,0,ms-1) if(f[s] == ans[x])
{
try(i,0,cnt-1)
if(!((s >> i) & 1) and !ji[i])
{ji[i] = 1; merge(x,son[i]);}
}
try(i,0,cnt-1) ans[x] += ans[son[i]];
}
inline short main()
{
file(select);
io >> n;
try(i,2,n)
{
register int x,y; io >> x >> y;
add(x,y); add(y,x);
}
io >> m;
try(i,1,m)
{
register int x,y; io >> x >> y;
vis[x][y] = vis[y][x] = 1;
}
dfs(1,0);
cout<<ans[1]<<endl;
return 0;
}
}
signed main() {return xin::main();}
表格
这个还是有一个部分分数的思路的。
就是我们发现3个点组成的曼哈顿距离之和就是将这些点围起来的最小的长方形的周长
那么一共就有 \((n-x+1)(m-y+1)\) 个长方形。
然后每个长方形中的三个点的位置关系就有 \((x-1)*(y-1)*3!\)
黑白
咕
打怪
贪心水过。。。。
然后没脸不说了。。。
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(a) FILE *FI = freopen(#a".in","r",stdin); FI = freopen(#a".out","w",stdout)
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define debug cout<<"debug"<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
char buf[1<<20],*p1 = buf,*p2 = buf; int ak; typedef long long ll; typedef unsigned long long ull;
class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &s)
{
register int f = 0;s = 0; register char ch = gc();
while(!isdigit(ch)) {f |= ch == '-'; ch = gc();}
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io;static const int maxn = 1e6+10,inf = 1e9+7;const ll llinf = 1e18+7;
#define int long long
auto max = [](int x,int y) -> int{return x > y ? x : y;}; auto min = [](int x,int y) -> int{return x < y ? x : y;};
namespace xin
{
class xin_data
{
public:
int hp,at,con,tim,id,c;
double pai;
int cheng;
}d[maxn];
int n,b;
bool vis[maxn];
inline short main()
{
file(fittest);
io >> n >> b;
try(i,1,n)
{
io >> d[i].at >> d[i].hp;
if(!d[i].hp) {n--;i--;continue;}
d[i].id = i;
d[i].c = (d[i].hp - 1) / b; d[i].cheng = d[i].c * d[i].at;
d[i].pai = (double)(1.0 * d[i].c + 1) / (1.0 * d[i].at);
}
std::sort(d+1,d+n+1,[](xin_data x,xin_data y) -> bool{return (x.cheng == y.cheng) ? x.at > y.at : x.cheng > y.cheng;});
vis[d[1].id] = vis[d[2].id] = 1;
// vis[1] = vis[5] = 1;
std::sort(d+1,d+n+1,[](xin_data x,xin_data y) -> bool{return x.pai < y.pai;});
auto check = []() -> int
{
int he = 0,ans = 0;
try(i,1,n) if(!vis[d[i].id]) he += d[i].at;
try(i,1,n) if(!vis[d[i].id])
{
// sb(d[i].at); jb(d[i].hp);
he -= d[i].at; ans += d[i].c * d[i].at;
ans += he * (d[i].c + 1);
}
int temp = ans;
// cout<<ans<<endl;
return ans;
};
int minn = check(); //jb(minn);
memset(vis,0,sizeof(bool) * (n + 1));
// vis[1] = vis[3] = 0;
if(n <= 200)
try(i,1,n) try(j,i+1,n)
{
vis[i] = vis[j] = 1;
minn = std::min(minn,check());
// sb(i); sb(j); jb(check());
vis[i] = vis[j] = 0;
// memset(vis,0,sizeof(vis));
}
cout<<minn<<endl;
return 0;
}
}
signed main() {return xin::main();}