[考试总结]noip模拟48
今天题目比较简单,所以有时间来写博客。。。
然后先从模拟48开始
啊这。。。。
记不太清自己的考场行为了,就简单说说题解吧。。。
lighthouse
这个就是一个挺简单的容斥,然后一个环排列就有了。
系数为 \((-1)\)
#include<bits/stdc++.h>
using std::endl; using std::cout;
#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 asm(i,x) for(register signed i=head[x];i;i=edge[i].next)
namespace xin_io
{
#define debug cout<<"debug"<<endl
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<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; typedef long long ll; typedef unsigned long long ull;
class xin_stream{public:template<typename type>xin_stream &operator >> (type &s)
{
register bool 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 = 1e7+10,inf = 1e9+10;
#define int long long
namespace xin
{
const int mod = 1e9+7;
int fac[maxn],n,m;
inline void pre_work() {fac[0] = 1; try(i,1,n) fac[i] = fac[i-1] * i % mod;}
inline int ksm(int x,int y)
{
register int ret = 1;
while(y)
{
if(y & 1) ret = ret * x % mod;
x = x * x % mod; y >>= 1;
}
return ret;
}
inline int count(int x)
{
int ret = 0;
while(x) ret += (x & 1),x >>= 1;
return ret;
}
class xin_data
{
public:
int x,y;
xin_data(){}
xin_data(int x,int y):x(x),y(y){}
}d[maxn]; int zhi = 0;
int ans = 0;
int fa[maxn],q[maxn],top;
inline int find(int x) {return fa[x] == x ? x : fa[x] = find(fa[x]);}
inline void merge(int x,int y)
{
if(x == y) return ;
fa[x] = y;
}
bool ji[maxn],shit[maxn];
int vis[maxn];
inline int work(int st)
{
// memset(vis,0,sizeof(bool) * (n + 1)); memset(fa,0,sizeof(int) * (n + 1));
// memset(ji,0,sizeof(bool) * (n + 1)); memset(shit,0,sizeof(bool) * (n + 1));
try(i,1,zhi) if((st >> (i - 1) & 1)) vis[d[i].x] = vis[d[i].y] = ji[d[i].x] = ji[d[i].y] = 0;
int ok = 0,temp = 0,zhuan = 0; top = 0; register int num = count(n);
try(i,1,zhi)
if(((st >> (i - 1)) & 1))
{
register int x = d[i].x,y = d[i].y;
shit[x] = 1; shit[y] = 1;
fa[x] = x; fa[y] = y;
q[++top] = i;
}
// try(i,1,n) if(!shit[i]) fa[i] = 0;
try(i,1,top)
{
register int x = d[q[i]].x,y = d[q[i]].y,fx = find(d[q[i]].x),fy = find(d[q[i]].y);
temp += !vis[x] + !vis[y];
if(fx == fy) ok = 1; merge(fx,fy);
if(vis[x] > 1 or vis[y] > 1) return 0;
vis[x] ++; vis[y] ++;
}
try(i,1,top)
{
register int x = find(d[q[i]].x);
if(!ji[x]) ji[x] = 1,zhuan++;
}
if(ok) if((zhuan > 1) or(num xor n)) return 0;
// sb(zhuan); jb(num);
int ret = fac[n + zhuan - temp - 1] * ksm(2,zhuan) % mod * ksm(2,mod - 2) % mod;
return ret;
}
bool fuck[maxn];
inline short main()
{
io >> n >> m;
/* if(!m)
{
ans = 1;
try(i,1,n) ans = ans * i % mod;
cout<<ans<<endl;
return 0;
}*/
try(i,1,n) fa[i] = i; int face;
try(i,1,m)
{
register int x,y; io >> x >> y;
d[++zhi] = xin_data(x,y);
merge(find(x),find(y));
face = x;
}
int jsq = 0;
try(i,1,n) if(!fuck[find(i)]) fuck[find(i)] = 1,jsq ++;
if(jsq == 1) {ans += (n >= 20 or (n == m and face == 3)); if(n <= 10 and m>=20) {cout<<0<<endl; return 0;}}
pre_work();
try(i,0,(1 << zhi) - 1)
{
if(count(i) & 1) //ji
ans = (ans - work(i) + mod) % mod;
else // ou
ans = (ans + work(i) + mod) % mod;
}
cout<<(ans + mod) % mod<<endl;
return 0;
}
}
signed main() {return xin::main();}
Minner
欧拉回路
假设图中有 \(k\)个联通块,然后第 \(i\) 个点的度为 \(c_i\),那么
\[Ans = \sum_{i=1}^{k}max(1,\frac {c_i}{2})-1
\]
第二问就是将度数为奇数的点任意配对连额外的边。
然后每个连通块跑欧拉回路,额外连的边会将回路割成若干段路径,这些路径之间以及连通块之间用1操作跳。
然后就是 \(\mathcal O(n + m)\)
#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 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;
int n,m;
namespace xin
{
class xin_edge{public:int next,ver,w;}edge[maxn];
int head[maxn],rp = 1;
inline void add(int x,int y,int z) {edge[++rp].ver = y;edge[rp].w = z; edge[rp].next = head[x]; head[x] = rp;}
int ind[maxn];
int num = 0,ret = 0,tot,c[maxn];
bool vis[maxn];
std::vector<int>vec[maxn];
void dfs(int x)
{
vis[x] = 1;
if(ind[x] & 1) ret ++,vec[tot].push_back(x),c[tot] ++;
go(i,x)
if(!vis[y])
dfs(y);
}
int temp[maxn],top = 0;
class xin_data
{
public:
int op,to;
xin_data(){}
xin_data(int to,int op):op(op),to(to){}
}ans[maxn],sta[maxn];
int zhi = 0,jsq = 0;
inline void oulalala()
{
sta[++zhi] = xin_data(vec[1][1],0);
while(zhi)
{
int x = sta[zhi].to,i = head[x];
while(i and vis[i]) i = edge[i].next;
if(i)
{
sta[++zhi] = xin_data(edge[i].ver,edge[i].w);
vis[i] = vis[i xor 1] = 1;
head[x] = edge[i].next;
}
else
ans[++jsq] = sta[zhi],--zhi;
}
}
inline short main()
{
try(i,1,m)
{
register int x,y; io >> x >> y;
add(x,y,0); add(y,x,0);
ind[x]++; ind[y]++;
}
try(i,1,n)
if(!vis[i] and head[i])
{
ret = 0; tot ++;vec[tot].push_back(0);
dfs(i);
if(!c[tot]) vec[tot].push_back(i),vec[tot].push_back(i);
num += std::max(c[tot]>>1,1);
}
try(i,3,c[1]) temp[++top] = vec[1][i];//,jb(vec[1][i]);
try(i,2,tot)
{
add(vec[i][1],vec[i-1][2],1); add(vec[i-1][2],vec[i][1],1);
try(j,3,c[i]) temp[++top] = vec[i][j];
}
for(register int i=2;i<=top;i+=2)
{
add(temp[i],temp[i-1],1);
add(temp[i-1],temp[i],1);
}
memset(vis,0,sizeof(vis));
oulalala();
cout<<num - 1<<endl;
printf("%d\n",ans[jsq].to);
throw(i,jsq-1,1)
printf("%d %d\n",ans[i].op,ans[i].to);
return 0;
}
}
signed main()
{
io >> n >> m;
xin::main();
return 0;
}
Lyk Love painting
似乎就是一个结论 \(dp\),忘了思路了。。。
#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];i;i=edge[i].next)
namespace xin_io
{
#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
namespace xin
{
int he1[maxn],he2[maxn],he3[maxn];
int n,m,l,r;
int f1[maxn],f2[maxn],f3[maxn];
int dp[maxn];
inline bool check(int x)
{
f1[0] = f2[0] = f3[0] = 0;
try(i,1,n)
{
f1[i] = f1[i-1]; f2[i] = f2[i-1]; f3[i] = f3[i-1];
while(he1[i] - he1[f1[i]] > x) f1[i] ++;
while(he2[i] - he2[f2[i]] > x) f2[i] ++;
while(he3[i] - he3[f3[i]] > x) f3[i] ++;
}
dp[0] = 0; try(i,1,n) dp[i] = m + 1;
try(i,1,n)
{
dp[i] = std::min(dp[i],dp[f3[i]]+1);
register int t1 = i,t2 = i,s = 0;
while(s + 1 <= m and (t1 or t2))
{
if(t1 > t2) t1 = f1[t1];
else t2 = f2[t2];s ++;
dp[i] = std::min(dp[i],dp[std::max(t1,t2)] + s);
}
if(dp[i] > m) return 0;
}
return 1;
}
inline short main()
{
io >> n >> m;
try(i,1,n)
{
register int x; io >> x; r += x; l = std::max(l,x);
he1[i] = he1[i-1] + x; he3[i] += x;
}
try(i,1,n)
{
register int x; io >> x; r += x; l = std::max(l,x);
he2[i] = he2[i-1] + x; he3[i] += x;
}
try(i,1,n) he3[i] += he3[i-1];
while(l != r - 1)
{
register int mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid;
}
if(check(l)) cout<<l<<endl;
else cout<<r<<endl;
return 0;
}
}
signed main() {return xin::main();}