ASC45
A
题意 要求构造集合$A,B$, 使得$A+A$与$B+B$相同
只有$n$为$2$的幂时合法, 构造可以初始化$A_0=1,B_0=2$
然后让$A_{i+2^x}=B_{i}+2^{x+1},B_{i+2^x}=A_{i}+2^{x+1}$
#include <bits/stdc++.h>
#define REP(_i,_a,_n) for(int _i=_a;_i<=_n;++_i)
#define PER(_i,_a,_n) for(int _i=_n;_i>=_a;--_i)
using namespace std;
int main() {
freopen("analogous.in","r",stdin);
freopen("analogous.out","w",stdout);
int n;
while (cin>>n,n) {
if ((n&-n)!=n) puts("No");
else {
puts("Yes");
vector<int> v[2];
v[0].push_back(1),v[1].push_back(2);
for (int x=2; v[0].size()!=n; x<<=1) {
int sz = v[0].size();
REP(i,0,sz-1) v[0].push_back(v[1][i]+x),v[1].push_back(v[0][i]+x);
}
for (int t:v[0]) cout<<t<<' ';puts("");
for (int t:v[1]) cout<<t<<' ';puts("");
}
}
}
B
题意 $f$为分段线性函数, 求最小的区间$[L,R]$, 满足$P(L\le \xi\le R | a\le f(\xi)\le b)\ge \alpha$
预处理出所有合法区间, 然后滑动区间
#include <iostream>
#include <queue>
#include <cmath>
using namespace std;
#define db double
#define abs(x) ((x)>0?(x):(-x))
#define LL long long
#define mp make_pair
#define pb push_back
#define fi first
#define se second
const db EPS = 1e-9;
const db INF = 1e18;
const db PI = acos(-1.0);
inline double torad(double deg) { return deg / 180 * PI; }//转弧度
inline int dcmp(double x)
{
if(fabs(x) < EPS) return 0;
return x < 0 ? -1 : 1;
}
struct Point{
db x, y;
Point(db _x = 0, db _y = 0) : x(_x), y(_y){}
inline void read(){
scanf("%lf %lf", &x, &y);
}
};
// 过两点p1, p2的直线一般方程ax+by+c=0
// (x2-x1)(y-y1) = (y2-y1)(x-x1)
inline void GetLineGeneralEquation(Point p1, Point p2, double &a, double &b, double &c)
{
a = p2.y - p1.y;
b = p1.x - p2.x;
c = -a * p1.x - b * p1.y;
}
const int N = 1e5+10;
int n;
Point p[N];
double a,b,x;
pair<double,double> f[N];
int main() {
freopen("bayes.in","r",stdin);
freopen("bayes.out","w",stdout);
while (scanf("%d", &n), n) {
scanf("%lf%lf%lf", &a, &b, &x);
for (int i=0; i<=n; ++i) {
scanf("%lf%lf", &p[i].x, &p[i].y);
}
int cnt = 0;
double tot = 0;
for (int i=1; i<=n; ++i) {
double u,v,w;
GetLineGeneralEquation(p[i-1],p[i],u,v,w);
double l = p[i-1].x, r = p[i].x;
//ax+by+c=0
//x=(-c-by)/a
double l1 = (-w-v*a)/u, r1 = (-w-v*b)/u;
if (l1>r1) swap(l1,r1);
l = max(l, l1), r = min(r, r1);
if (l<=r) f[++cnt] = {l,r}, tot += r-l;
}
tot *= x;
int now = 1;
double l, r, len = 0;
double ans = 1e18;
for (int i=1; i<=cnt; ++i) {
if (f[i].second-f[i].first>=tot) {
l = f[i].first, r = f[i].first+tot;
break;
}
while (now<=cnt&&len<tot) {
len += f[now].second-f[now].first;
++now;
}
if (len>=tot) {
double ret = f[now-1].second-f[i].first-len+tot;
if (ret<ans) ans = ret, l = f[i].first, r = f[now-1].second-len+tot;
}
len -= f[i].second-f[i].first;
}
printf("%.12lf %.12lf\n", l, r);
}
}
C
题意 求所有长$n$, 不存在$i<j<k$使得$a_k<a_i<a_j$的$ascent\space sequences$个数
从前往后填数, 维护每种数出现的状态, 始终把当前能填的最小数当做最低位, 可以发现状态会有很多重复的, 记忆化一下就可以了
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef tuple<int,int,int,ll> state; map<state,ll> mp; ll solve(int d, int mx, int pre, ll s) { state now(d,mx,pre,s); if (mp.count(now)) return mp[now]; if (!d) return 1; ll ans = 0; int mi = 0; for (int i=0; i<=mx; ++i) { ans += solve(d-1,mx-mi+(i>pre),i-mi,(s|1ll<<i)>>mi); if (s>>i&1) mi = i; } return mp[now]=ans; } int main() { freopen("catalian.in","r",stdin); freopen("catalian.out","w",stdout); int n, clk = 0; while (cin>>n,n) cout<<"Case #"<<clk<<": "<<solve(n-1,1,0,1)<<endl; }
D
题意 要求构造一个$n$点的有向图, 点$n-1$是家, 点$n$是酒吧, 其余点出度为$2$, 初始有一个酒鬼在点$1$, 每一步酒鬼等概率走向一个点, 要求最终酒鬼回家的概率为$\frac{p}{q}$
考虑二进制即可, 比如$q=13$, 那么构造$f=\frac{f}{16}+\frac{f}{8}+\frac{1}{4}+\frac{1}{2}$, $f=\frac{12}{13}$
那么就可以用$\lceil\log_2{q}\rceil$个点构造出$\frac{q-1}{q}$, 然后再递归构造$\frac{q-2}{q-1}$, 以此类推
这样构造出$\frac{p}{q}$大约要$q\lceil\log_2{q}\rceil\le 1000$可以满足条件
#include <bits/stdc++.h>
#define REP(_i,_a,_n) for(int _i=_a;_i<=_n;++_i)
#define PER(_i,_a,_n) for(int _i=_n;_i>=_a;--_i)
using namespace std;
const int N = 1e5+10;
int tot,L[N],R[N],f[N],g[N],ID[N];
int solve(int p, int q, int s) {
int x = 1;
while ((1<<x)<q) ++x;
int y = (1<<x)-q, now = tot+1;
PER(i,0,x-1) {
++tot;
L[tot] = y>>i&1?now:s;
R[tot] = i?tot+1:1;
}
if (p!=q-1) return solve(p,q-1,now);
return now;
}
void gao(int x, int y) {
if (x==y) return;
REP(i,1,tot) {
if (L[i]==x) f[i] = y;
else if (L[i]==y) f[i] = x;
else f[i] = L[i];
if (R[i]==x) g[i] = y;
else if (R[i]==y) g[i] = x;
else g[i] = R[i];
}
REP(i,1,tot) {
if (i==x) L[i] = f[y], R[i] = g[y];
else if (i==y) L[i] = f[x], R[i] = g[x];
else L[i] = f[i], R[i] = g[i];
}
REP(i,1,tot) {
if (ID[i]==x) ID[i] = y;
else if (ID[i]==y) ID[i] = x;
}
}
int main() {
freopen("drunkard.in","r",stdin);
freopen("drunkard.out","w",stdout);
int p,q;
while (cin>>p>>q,p||q) {
L[1] = R[1] = L[2] = R[2] = 0;
tot = 2;
int x = solve(p,q,2);
REP(i,1,tot) ID[i] = i;
gao(1,x),gao(tot-1,ID[2]),gao(tot,ID[1]);
printf("%d\n", tot);
REP(i,1,tot-2) printf("%d %d\n",L[i],R[i]);
}
}
F
题意 给定一个$n$点$m$条边的图, 保证点$1$与其他所有点相连, 要求给每条边标号, 使得标号是$[1,m]$的排列, 并且每个点邻接边标号和不相同
先将与$1$不与$1$相连的边赋任意权值, 然后排序通过与$1$相连的边调整即可
#include <bits/stdc++.h>
#define REP(_i,_a,_n) for(int _i=_a;_i<=_n;++_i)
#define PER(_i,_a,_n) for(int _i=_n;_i>=_a;--_i)
using namespace std;
typedef long long ll;
const int N = 1e6+10;
int n, m, f[N], ID[N];
pair<ll,int> val[N];
int main() {
freopen("flights.in","r",stdin);
freopen("flights.out","w",stdout);
while (scanf("%d%d", &n, &m), n||m) {
REP(i,1,n) val[i].first=0,val[i].second=i;
int now = 1;
REP(i,1,m) {
int u, v;
scanf("%d%d", &u, &v);
if (u>v) swap(u,v);
if (u!=1) {
val[u].first += now;
val[v].first += now;
f[i] = now;
++now;
}
else ID[v] = i;
}
sort(val+1,val+1+n);
REP(i,2,n) f[ID[val[i].second]]=now++;
puts("Yes");
REP(i,1,m) printf("%d ", f[i]);puts("");
}
}