直接粘题解tmd
A.伯爵
我们发现一对排列不一定对应一种方案,一种方案也不一定对应一对排列。
考虑如何不算重。
首先确定的是归并方式:每个排列对应一些划分,相当于把每个划分出的区间按最大值排序。
考虑把\(1..n\)划分成若干集合,使得每个集合在两个排列中都对应若干区间的并,且是极小的。
当然枚举完以后还要讨论集合内的排列方式。
那么这样一种方案对应的排列对的个数为\(2^{不完全相同的集合数}\)
对应的答案序列个数为\(2^{最大值相同但整体不同的划分数}\)
考虑令\(f_i\)表示\(\sum_{一对长度为i的排列使得不能划分成更小的集合}2^{最大值相同但整体不同的划分数}\)
考虑
\[F=\sum_{i\ge 1}{f_i\over i!} \]可以发现
\[n![x^n]e^{2F}=\sum_{长度为n的排列对}2^{最大值相同的划分数}=\prod_{i=1}^{n}(i^2+1) \\ \]后面部分的证明考虑1产生的贡献。
发现答案就是\(n![x^n]e^F\)。多项式开根即可。
B.给给的游戏
题目描述
给定 \(n\) 个点的竞赛图 \(G\),对于每条边 \((i,j)\),求解反转该边方向后图 \(G\) 是否联通。
\(1 \leq n \leq 5000\)
文字题解
问题 \(1\):求解竞赛图的一条哈密顿路径
假设求出前 \(i\) 个点的哈密顿路径,加入第 \(i+1\) 个点
- 若存在边 \((i+1,v_1)\) 则将 \(i+1\) 放在 \(v_1\) 之前
- 若存在边 \((v_i,i+1)\) 则将 \(i+1\) 放在 \(v_i\) 之后
- 否则必然存在 \(v_j,v_{j+1}\),满足存在边 \((v_j,i+1),(v_{j+1},i+1)\) 将其插入
问题 \(2\) :求解强连通竞赛图的一条哈密顿回路
我们先求解出一条哈密顿路径,在其之上构造
首先一定存在哈密顿路径的一个前缀满足其构成回路,否则每个点一定均向哈密顿路径之后的点连边,那么图不强连通
之后每次将后面一段未加入回路的路径尝试插入回路中,容易发现最终所有点一定在回路中,证明留作习题
考虑若原图不强连通,那么一定是首尾 \(2\) 个联通块的翻转构成答案 (注意特判 \(n=2\) 的情况)
否则原图强联通,容易发现除去哈密顿回路的边一定满足,我们只需要求解哈密顿回路上的每条边是否可行即可
关于竞赛图是否强联通,可以将所有点按度数排序,尝试比较是否每前 \(i\) 个点向后 \(n-i\) 个点的连边数均为\(i \times (n-i)\),若存在则一定不联通,否则一定联通,证明留作习题。
容易发现反转一条边,可以直接维护增量,复杂度为 \(O(n^2)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N=5007; bool tag[N];
int n,k,p[N],w[N],g[N],v[N],q[N],ga[N],gb[N],deg[N],f[N][N],t[N][N]; char s[N];
inline int getval(char w){
if('0'<=w&&w<='9') return w-'0'; return 10+w-'A';
}
inline char getvas(int w){
if(0<=w&&w<=9) return w+'0'; return w-10+'A';
}
inline bool cmp(int a,int b){
return deg[a]>deg[b];
}
inline void solve(int a,int b,int c){
g[0]=0; int t=1;
while(a--) g[++g[0]]=w[t++]; g[++g[0]]=b;
while(c--) g[++g[0]]=w[t++]; for(int x=0;x<=g[0];x++) w[x]=g[x];
}
inline void solve2(int s,int a,int b){
g[0]=0; int t=1,e=a-s-1;
while(s--) g[++g[0]]=q[t++];
for(int i=a;i<=b;i++) g[++g[0]]=w[i];
while(e--) g[++g[0]]=q[t++];
for(int x=0;x<=g[0];x++) q[x]=g[x];
}
inline void solve3(int a,int b){
f[a][b]^=1,f[b][a]^=1;
g[0]=0,w[0]=0; bool f1=0,f2=0; int c=a,d=b; deg[a]--,deg[b]++;
if(deg[a]<deg[b]) swap(a,b);
for(int i=1;i<=p[0];i++){
if(p[i]==a||p[i]==b) continue; g[++g[0]]=p[i];
}
for(int i=1;i<=g[0];i++){
if(deg[a]>=deg[g[i]]&&!f1) f1=1,w[++w[0]]=a;
if(deg[b]>=deg[g[i]]&&!f2) f2=1,w[++w[0]]=b;
w[++w[0]]=g[i];
}
if(!f1) w[++w[0]]=a; if(!f2) w[++w[0]]=b; g[0]=0; f1=0,f2=0;
for(int i=1;i<w[0];i++){
g[i]=g[i-1];
if(w[i]==a||w[i]==b){
if(w[i]==a) f1=1; if(w[i]==b) f2=1;
for(int x=1;x<i;x++) if(f[w[x]][w[i]]) g[i]--;
for(int x=i+1;x<=w[0];x++) if(f[w[i]][w[x]]) g[i]++;
}
else{
g[i]=g[i]-ga[w[i]]+gb[w[i]];
g[i]=g[i]+(f[a][w[i]]&&v[a]<v[w[i]]);
g[i]=g[i]+(f[b][w[i]]&&v[b]<v[w[i]]);
g[i]=g[i]-(f[w[i]][a]&&v[a]>v[w[i]]);
g[i]=g[i]-(f[w[i]][b]&&v[b]>v[w[i]]);
g[i]=g[i]-(f[a][w[i]]&&f1);
g[i]=g[i]-(f[b][w[i]]&&f2);
g[i]=g[i]+(f[w[i]][a]&&!f1);
g[i]=g[i]+(f[w[i]][b]&&!f2);
}
if(g[i]==i*(w[0]-i)){
f[a][b]^=1,f[b][a]^=1,t[a][b]=t[b][a]=0;
deg[c]++,deg[d]--; return;
}
}
deg[c]++,deg[d]--,f[a][b]^=1,f[b][a]^=1; return;
}
int main(){
int case_num; cin>>case_num;
while(case_num--){
scanf("%d",&n),p[1]=1;
for(int i=2;i<=n;i++){
scanf("%s",s+1),k=strlen(s+1),deg[i]=0,p[i]=i;
for(int j=1;j<=k;j++){
s[j]=getval(s[j]);
if(j*4-3<i){
f[i][j*4-3]=((s[j]&1)>0)?1:0;
f[j*4-3][i]=((s[j]&1)>0)?0:1;
}
if(j*4-2<i){
f[i][j*4-2]=((s[j]&2)>0)?1:0;
f[j*4-2][i]=((s[j]&2)>0)?0:1;
}
if(j*4-1<i){
f[i][j*4-1]=((s[j]&4)>0)?1:0;
f[j*4-1][i]=((s[j]&4)>0)?0:1;
}
if(j*4-0<i){
f[i][j*4-0]=((s[j]&8)>0)?1:0;
f[j*4-0][i]=((s[j]&8)>0)?0:1;
}
}
}
if(n==2){
puts("0"); continue;
}
for(int i=1;i<=n;i++) deg[i]=0;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(f[i][j]) deg[i]++; else deg[j]++;
sort(p+1,p+n+1,cmp); bool flag=0; p[0]=n;
for(int i=1;i<=n;i++) v[p[i]]=i; g[0]=0; ga[p[n]]=gb[p[n]]=0;
for(int i=1;i<n;i++){
g[i]=g[i-1],ga[p[i]]=gb[p[i]]=0;
for(int x=1;x<i;x++) if(f[p[x]][p[i]]) g[i]--,ga[p[i]]++;
for(int x=i+1;x<=n;x++) if(f[p[i]][p[x]]) g[i]++,gb[p[i]]++;
tag[i]=(g[i]<i*(n-i)); if(!tag[i]) flag=1;
}
if(flag){
int a=0,b=0;
for(int i=n;i>=1;i--) if(!tag[i]) a=i;
for(int i=1;i<n;i++) if(!tag[i]) b=i+1;
for(int i=1;i<=a;i++)
for(int j=b;j<=n;j++)
if(p[i]>p[j]) t[p[i]][p[j]]=1;
else t[p[j]][p[i]]=1;
}
else{
w[w[0]=1]=1;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++) t[j][i]=1;
for(int i=2;i<=n;i++){
if(f[i][w[1]]) solve(0,i,w[0]);
else if(f[w[w[0]]][i]) solve(w[0],i,0);
else{
for(int x=1;x<w[0];x++)
if(f[w[x]][i]&&f[i][w[x+1]]) {solve(x,i,w[0]-x); break;}
}
}
int j; q[0]=0;
for(int i=2;i<=n;i++) if(f[w[i]][w[1]]) j=i;
for(int i=1;i<=j;i++) q[++q[0]]=w[i];
for(int i=j+1;i<=n;i++){
for(int x=1;x<j;x++)
if(f[q[x]][w[j+1]]&&f[w[i]][q[x+1]]){
solve2(x,j+1,i),j=i; break;
}
if(i==j) continue;
if(f[q[j]][w[j+1]]&&f[w[i]][q[1]]) solve2(j,j+1,i);
}
for(int i=1;i<n;i++) solve3(q[i],q[i+1]); solve3(q[n],q[1]);
}
for(int i=2;i<=n;i++){
for(int j=1;(j-1)*4<i-1;j++)
putchar(getvas(t[i][j*4-3]+2*t[i][j*4-2]+4*t[i][j*4-1]+8*t[i][j*4]));
puts("");
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) t[i][j]=0;
}
return 0;
}
C.一定要关掉
对目录的遍历即为对二叉树的遍历,显然 DLR
为前序遍历,LDR
为中序遍历,LRD
为后序遍历。
-
所有排列都能转化成上述三种,例如
RLD
与DLR
等价,因为它们的序列一定相反。 -
由初赛常识,知前中得后,知后中得前,知前后不得中,例如一条链。
答案不超过 \(2\),模拟即可。
D.种树
相当于一下午就改了这一个题,注意要分正负维护保证复杂度,取min操作时要注意其对之后的影响,该还给后边的还得还回去
直接结合题解看码吧,map好维护一点,脑抽了信题解写了set,其实应该是multiset,但是居然没被卡,后来改成multi了
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i)
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;
const int maxn=5e5+10;
const int INF=1e6+10;
struct Line{
int a,b,c,d,id;
ll Calc(int x)const{ return 1LL*(x-a)*(d-b)+1LL*b*(c-a); }
bool operator <(const Line&rhs)const{
if(rhs.a<a)return 1LL*b*(rhs.c-rhs.a)<rhs.Calc(a);
else return 1LL*Calc(rhs.a)<1LL*rhs.b*(c-a);
}
}P[maxn];
int n,L,R;
vector<int>E[maxn];
int deg[maxn];
void Link(){
set<Line>S;priority_queue<pii>q;
Rep(i,1,n){
while(!q.empty() && -q.top().fir<P[i].a){ S.erase(P[q.top().sec]);q.pop(); }
auto it = S.lower_bound(P[i]);
if(it!=S.end()){ E[it->id].emplace_back(i); ++deg[i]; }
if(it!=S.begin()){ E[i].emplace_back(prev(it)->id),++deg[prev(it)->id]; }
S.insert(P[i]);q.emplace(-P[i].c,i);
}
}
void Dp(){
multiset<pii>f,g;
f.insert(pii(0,INF)),g.insert(pii(L-1,-INF));
f.insert(pii(R,INF));
queue<int>q;Rep(i,1,n)if(!deg[i])q.push(i);
auto tmp=f.begin();
while(!q.empty()){
int u=q.front();q.pop();
if(P[u].b>P[u].d){
auto it = f.lower_bound(pii(P[u].a+1,-INF));
int sum=0;vector< set<pii>::iterator >vec;
for(; it!=f.end() && it->fir<=P[u].c; ++it ){
sum+=it->sec;vec.emplace_back(it);
auto ip=g.lower_bound(pii(it->fir,-INF));
if(ip==g.end())continue;
while(ip!=g.end() && sum+ip->sec>=0 && ip->fir<=P[u].c){
sum+=ip->sec;tmp=next(ip);
g.erase(ip);ip=tmp;
}
if(sum >0 && ip!=g.end() && ip->fir<=P[u].c){
int p=ip->fir;
sum+=ip->sec;
g.erase(ip);g.insert(pii(p,sum));
sum=0;
}
}
for(auto ip : vec)f.erase(ip);
if(sum>0)f.insert(pii(P[u].c+1,sum));
f.insert(pii(P[u].a,1));g.insert(pii(P[u].c,-1));
}else{
auto it = g.upper_bound(pii(P[u].c-1,INF+INF));
if(it!=g.begin()){
--it;
int sum=0;vector< set<pii>::iterator >vec;
for(; it->fir>=P[u].a ; --it){
sum+=it->sec;vec.emplace_back(it);
auto ip=f.upper_bound(pii(it->fir,INF));
if(ip!=f.begin()){
--ip;
while(ip->fir>=P[u].a && sum+ip->sec<=0){
sum+=ip->sec;
if(ip==f.begin()){ f.erase(ip); break; }
tmp=prev(ip);f.erase(ip);ip=tmp;
}
if(sum<0 && ip!=f.end() && ip->fir>=P[u].a){
int p=ip->fir;
sum+=ip->sec;
f.erase(ip);f.insert(pii(p,sum));
sum=0;
}
}
if(it==g.begin())break;
}
for(auto ip : vec)g.erase(ip);
if(sum<0)g.insert(pii(P[u].a,sum));
}
f.insert(pii(P[u].a+1,1)),g.insert(pii(P[u].c+1,-1));
}
for(auto v : E[u])!(--deg[v]) && (q.push(v),0);
}
int ans=n;int sum=0;
f.insert(pii(L,0));f.insert(pii(R,0));
f.insert(g.begin(),g.end());
for(auto it=f.begin();it!=f.end();++it){
sum+=it->sec;
if((it->fir>=L && it->fir<=R) && (it==f.end() || it->fir !=(next(it)->fir)))ans=min(ans,sum);
}
cout<<ans<<"\n";
}
void solve(){
cin>>L>>R>>n;Rep(i,1,n)cin>>P[i].a>>P[i].b>>P[i].c>>P[i].d;
Rep(i,1,n)if(P[i].a>P[i].c)swap(P[i].a,P[i].c),swap(P[i].b,P[i].d);
sort(P+1,P+n+1,[&](const Line &x,const Line &y){ return x.a<y.a; });
L*=2,R*=2;Rep(i,1,n)P[i].id=i,P[i].a*=2,P[i].b*=2,P[i].c*=2,P[i].d*=2;
Link();
Dp();
}
int main (){
fre(tree);
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0;
}
标签:pii,39,省选,ip,sum,++,int,联测,&&
From: https://www.cnblogs.com/Delov/p/17153035.html