《Denso Create Programming Contest 2022(AtCoder Beginner Contest 239)》
A:
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 1e6 + 5; const int M = 1e7 + 5; const LL Mod = 998244353; #define rep(at,am,as) for(int at = am;at <= as;++at) #define INF 1e18 #define dbg(ax) cout << "now this num is " << ax << endl; inline long long ADD(long long x,long long y) { if(x + y < 0) return ((x + y) % Mod + Mod) % Mod; return (x + y) % Mod; } inline long long MUL(long long x,long long y) { if(x * y < 0) return ((x * y) % Mod + Mod) % Mod; return x * y % Mod; } inline long long DEC(long long x,long long y) { if(x - y < 0) return (x - y + Mod) % Mod; return (x - y) % Mod; } void solve() { double x;cin >> x; double ans = sqrt(x * (12800000 + x)); printf("%.10f\n",ans); } int main() { // int _; // for(scanf("%d",&_);_;_--) { solve(); //} // system("pause"); return 0; }
B:
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 1e6 + 5; const int M = 1e7 + 5; const LL Mod = 998244353; #define rep(at,am,as) for(int at = am;at <= as;++at) #define INF 1e18 #define dbg(ax) cout << "now this num is " << ax << endl; inline long long ADD(long long x,long long y) { if(x + y < 0) return ((x + y) % Mod + Mod) % Mod; return (x + y) % Mod; } inline long long MUL(long long x,long long y) { if(x * y < 0) return ((x * y) % Mod + Mod) % Mod; return x * y % Mod; } inline long long DEC(long long x,long long y) { if(x - y < 0) return (x - y + Mod) % Mod; return (x - y) % Mod; } void solve() { LL x;cin >> x; if(x >= 0) { printf("%lld\n",x / 10); } else { if(x % 10 == 0) printf("%lld\n",x / 10); else printf("%lld\n",x / 10 - 1); } } int main() { // int _; // for(scanf("%d",&_);_;_--) { solve(); //} // system("pause"); return 0; }
C:这题直接上几何板子求一下两圆交点就好了
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 1e6 + 5; const int M = 1e7 + 5; const LL Mod = 998244353; #define rep(at,am,as) for(int at = am;at <= as;++at) #define INF 1e18 #define dbg(ax) cout << "now this num is " << ax << endl; inline long long ADD(long long x,long long y) { if(x + y < 0) return ((x + y) % Mod + Mod) % Mod; return (x + y) % Mod; } inline long long MUL(long long x,long long y) { if(x * y < 0) return ((x * y) % Mod + Mod) % Mod; return x * y % Mod; } inline long long DEC(long long x,long long y) { if(x - y < 0) return (x - y + Mod) % Mod; return (x - y) % Mod; } double eps = 1e-10; const double pi=acos(-1.0); //判断正负 int sgn(double x) { if (fabs(x)<eps) return 0; if (x<0) return -1; else return 1; } //平方 inline double sqr(double x) { return x*x; } struct Point { double x,y; Point() {} Point(double _x, double _y) { x=_x; y=_y; } void input() { scanf("%lf%lf",&x,&y); } void output() { printf("%.2f%.2f\n",x,y); } bool operator == (Point b)const { return sgn(x-b.x)==0 && sgn(y-b.y)==0; } bool operator < (Point b)const { return sgn(x-b.x)==0?sgn(y-b.y)<0:x<b.x; } Point operator -(const Point &b)const { return Point(x-b.x,y-b.y); } //叉积 double operator ^(const Point &b)const { return x*b.y-y*b.x; } //点积 double operator *(const Point &b)const { return x*b.x+y*b.y; } //返回长度 double len() { return hypot(x,y); } //返回长度平方 double len2() { return x*x+y*y; } //返回两点间距 double distance(Point p) { return hypot(x-p.x,y-p.y); } Point operator +(const Point &b)const { return Point(x+b.x,y+b.y); } Point operator *(const double &k)const { return Point(x*k,y*k); } Point operator /(const double &k)const { return Point(x/k,y/k); } //pa和pb的夹角 double rad(Point a,Point b) { Point p=*this; return fabs(atan2(fabs((a-p)^(b-p)),(a-p)*(b-p))); } //化为长度为r的向量 Point trunc(double r) { double l=len(); if (!sgn(l)) return *this; r/=l; return Point(x*r,y*r); } //逆时针旋转 90 度 Point rotleft() { return Point(-y,x); } //顺时针旋转 90 度 Point rotright() { return Point(y,-x); } //绕着 p 点逆时针旋转 angle Point rotate(Point p,double angle) { Point v=(*this)-p; double c=cos(angle),s=sin(angle); return Point(p.x+v.x*c-v.y*s,p.y+v.x*s+v.y*c); } }; struct Line { Point s,e; Line() {} Line(Point _s,Point _e) { s=_s; e=_e; } bool operator ==(Line v) { return (s==v.s) && (e==v.e); } //根据一个点和倾斜角 angle 确定直线,0<=angle<π Line(Point p, double angle) { s=p; if (sgn(angle-pi/2)==0) { e=(s+Point(0,1)); } else { e=(s+Point(1,tan(angle))); } } //ax+by+c=0 Line(double a,double b,double c) { if(sgn(a)==0) { s=Point(0,-c/b); e=Point(1,-c/b); } else if(sgn(b)==0) { s=Point(-c/a,0); e=Point(-c/a,1); } else { s=Point(0,-c/b); e=Point(1,(-c-a)/b); } } void input() { s.input(); e.input(); } void adjust() { if(e<s) swap(s,e); } //求线段长度 double length() { return s.distance(e); } //返回直线倾斜角 0<=angle<π double angle() { double k=atan2(e.y-s.y,e.x-s.x); if(sgn(k)<0) k+=pi; if(sgn(k-pi)==0) k-= pi; return k; } //点和直线关系 // 1 在左侧 // 2 在右侧 // 3 在直线上 int relation(Point p) { int c=sgn((p-s)^(e-s)); if(c<0) return 1; else if(c>0) return 2; else return 3; } //点在线段上的判断 bool pointonseg(Point p) { return sgn((p-s)^(e-s))==0 && sgn((p-s)*(p-e))<=0; } //两向量平行 (对应直线平行或重合) bool parallel(Line v) { return sgn((e-s)^(v.e-v.s))==0; } //两线段相交判断 //2 规范相交 //1 非规范相交 //0 不相交 int segcrossseg(Line v) { int d1=sgn((e-s)^(v.s-s)); int d2=sgn((e-s)^(v.e-s)); int d3=sgn((v.e-v.s)^(s-v.s)); int d4=sgn((v.e-v.s)^(e-v.s)); if((d1^d2)==-2&&(d3^d4)==-2)return 2; return (d1==0 && sgn((v.s-s)*(v.s-e))<=0) || (d2==0 && sgn((v.e-s)*(v.e-e))<=0) || (d3==0 && sgn((s-v.s)*(s-v.e))<=0) || (d4==0 && sgn((e-v.s)*(e-v.e))<=0); } //直线和线段相交判断 //-*this line -v seg //2 规范相交 //1 非规范相交 //0 不相交 int linecrossseg(Line v) { int d1=sgn((e-s)^(v.s-s)); int d2=sgn((e-s)^(v.e-s)); if((d1^d2)==-2) return 2; return (d1==0||d2==0); } //两直线关系 //0 平行 //1 重合 //2 相交 int linecrossline(Line v) { if((*this).parallel(v)) return v.relation(s)==3; return 2; } //求两直线的交点 //要保证两直线不平行或重合 Point crosspoint(Line v) { double a1 = (v.e-v.s)^(s-v.s); double a2 = (v.e-v.s)^(e-v.s); return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1 )); } //点到直线的距离 double dispointtoline(Point p) { return fabs((p-s)^(e-s))/length(); } //点到线段的距离 double dispointtoseg(Point p) { if(sgn((p-s)*(e-s))<0 || sgn((p-e)*(s-e))<0) return min(p.distance(s),p.distance(e)); return dispointtoline(p); } //返回线段到线段的距离 //前提是两线段不相交,相交距离就是 0 了 double dissegtoseg(Line v) { return min(min(dispointtoseg(v.s),dispointtoseg(v.e)),min(v .dispointtoseg(s),v.dispointtoseg(e))); } //返回点 p 在直线上的投影 Point lineprog(Point p) { return s + ( ((e-s)*((e-s)*(p-s)))/((e-s).len2()) ); } //返回点 p 关于直线的对称点 Point symmetrypoint(Point p) { Point q = lineprog(p); return Point(2*q.x-p.x,2*q.y-p.y); } }; struct circle { Point p; //圆心 double r; //半径 circle() {} circle(Point _p,double _r) { p=_p; r=_r; } circle(double x,double y,double _r) { p=Point(x,y); r=_r; } //三角形的外接圆 //需要 Point 的 + / rotate() 以及 Line 的 crosspoint() //利用两条边的中垂线得到圆心 circle(Point a,Point b,Point c) { Line u=Line((a+b)/2,((a+b)/2)+((b-a).rotleft())); Line v=Line((b+c)/2,((b+c)/2)+((c-b).rotleft())); p=u.crosspoint(v); r=p.distance(a); } //三角形的内切圆 //参数 bool t 没有作用,只是为了和上面外接圆函数区别 circle(Point a,Point b,Point c,bool t) { Line u,v; double m=atan2(b.y-a.y,b.x-a.x),n=atan2(c.y-a.y,c.x-a.x); u.s=a; u.e=u.s+Point(cos((n+m)/2),sin((n+m)/2)); v.s=b; m=atan2(a.y-b.y,a.x-b.x),n=atan2(c.y-b.y,c.x-b.x); v.e=v.s+Point(cos((n+m)/2),sin((n+m)/2)); p=u.crosspoint(v); r=Line(a,b).dispointtoseg(p); } void input() { p.input(); scanf("%lf",&r); } void output() { printf("%.2lf-%.2lf-%.2lf\n",p.x,p.y,r); } bool operator == (circle v) { return (p==v.p) && sgn(r-v.r)==0; } bool operator < (circle v)const { return ((p<v.p) || ((p==v.p) && sgn(r-v.r)<0)); } //面积 double area() { return pi*r*r; } //周长 double circumference() { return 2*pi*r; } //点和圆的关系 //0 圆外 //1 圆上 //2 圆内 int relation(Point b) { double dst=b.distance(p); if (sgn(dst-r)<0) return 2; else if (sgn(dst-r)==0) return 1; return 0; } //线段和圆的关系 //比较的是圆心到线段的距离和半径的关系 int relationseg(Line v) { double dst=v.dispointtoseg(p); if (sgn(dst-r)<0) return 2; else if (sgn(dst-r)==0) return 1; return 0; } //直线和圆的关系 //比较的是圆心到直线的距离和半径的关系 int relationline(Line v) { double dst=v.dispointtoline(p); if (sgn(dst-r)<0) return 2; else if (sgn(dst-r)==0) return 1; return 0; } //两圆的关系 //5 相离 //4 外切 //3 相交 //2 内切 //1 内含 //需要 Point 的 distance int relationcircle(circle v) { double d=p.distance(v.p); if (sgn(d-r-v.r)>0) return 5; if (sgn(d-r-v.r)==0) return 4; double l=fabs(r-v.r); if (sgn(d-r-v.r)<0 && sgn(d-l)>0) return 3; if (sgn(d-l)==0) return 2; if (sgn(d-l)<0) return 1; } //求两个圆的交点,返回 0 表示没有交点,返回 1 是一个交点,2 是两个交点 //需要 relationcircle int pointcrosscircle(circle v,Point &p1,Point &p2) { int rel=relationcircle(v); if (rel==1 || rel==5)return 0; double d=p.distance(v.p); double l=(d*d+r*r-v.r*v.r)/(2*d); double h=sqrt(r*r-l*l); Point tmp=p+(v.p-p).trunc(l); p1=tmp+((v.p-p).rotleft().trunc(h)); p2=tmp+((v.p-p).rotright().trunc(h)); if(rel==2 || rel==4) return 1; return 2; } //求直线和圆的交点,返回交点个数 int pointcrossline(Line v,Point &p1,Point &p2) { if (!(*this).relationline(v)) return 0; Point a=v.lineprog(p); double d=v.dispointtoline(p); d=sqrt(r*r-d*d); if (sgn(d)==0) { p1=a; p2=a; return 1; } p1=a+(v.e-v.s).trunc(d); p2=a-(v.e-v.s).trunc(d); return 2; } //得到过 a,b 两点,半径为 r1 的两个圆 int gercircle(Point a,Point b,double r1,circle &c1,circle &c2) { circle x(a,r1),y(b,r1); int t=x.pointcrosscircle(y,c1.p,c2.p); if (!t) return 0; c1.r=c2.r=r; return t; } //得到与直线 u 相切,过点 q, 半径为 r1 的圆 int getcircle(Line u,Point q,double r1,circle &c1,circle &c2) { double dis = u.dispointtoline(q); if (sgn(dis-r1*2)>0) return 0; if (sgn(dis)==0) { c1.p=q+((u.e-u.s).rotleft().trunc(r1)); c2.p=q+((u.e-u.s).rotright().trunc(r1)); c1.r=c2.r=r1; return 2; } Line u1=Line((u.s+(u.e-u.s).rotleft().trunc(r1)),(u.e+(u.e-u.s).rotleft().trunc(r1))); Line u2=Line((u.s + (u.e-u.s).rotright().trunc(r1)),(u.e+(u.e-u.s).rotright().trunc(r1))); circle cc=circle(q,r1); Point p1,p2; if (!cc.pointcrossline(u1,p1,p2)) cc.pointcrossline(u2,p1,p2); c1=circle(p1,r1); if (p1==p2) { c2=c1; return 1; } c2=circle(p2,r1); return 2; } //同时与直线 u,v 相切,半径为 r1 的圆 int getcircle (Line u,Line v,double r1,circle &c1,circle &c2,circle &c3,circle &c4) { if(u.parallel(v))return 0;//两直线平行 Line u1=Line(u.s+(u.e-u.s).rotleft().trunc(r1),u.e+(u.e-u.s).rotleft().trunc(r1)); Line u2=Line(u.s+(u.e-u.s).rotright().trunc(r1),u.e+(u.e-u.s).rotright().trunc(r1)); Line v1=Line(v.s+(v.e-v.s).rotleft().trunc(r1),v.e+(v.e-v.s).rotleft().trunc(r1)); Line v2=Line(v.s+(v.e-v.s).rotright().trunc(r1),v.e+(v.e-v.s).rotright().trunc(r1)); c1.r=c2.r=c3.r=c4.r=r1; c1.p=u1.crosspoint(v1); c2.p=u1.crosspoint(v2); c3.p=u2.crosspoint(v1); c4.p=u2.crosspoint(v2); return 4; } //同时与不相交圆 cx,cy 相切,半径为 r1 的圆 int getcircle(circle cx,circle cy,double r1,circle &c1,circle &c2) { circle x(cx.p,r1+cx.r),y(cy.p,r1+cy.r); int t=x.pointcrosscircle(y,c1.p,c2.p); if (!t) return 0; c1.r=c2.r=r1; return t; } //过一点作圆的切线 (先判断点和圆的关系) int tangentline(Point q,Line &u,Line &v) { int x=relation(q); if (x==2) return 0; if (x==1) { u=Line(q,q+(q-p).rotleft()); v=u; return 1; } double d=p.distance(q); double l=r*r/d; double h=sqrt(r*r-l*l); u=Line(q,p+((q-p).trunc(l)+(q-p).rotleft().trunc(h))); v=Line(q,p+((q-p).trunc(l)+(q-p).rotright().trunc(h))); return 2; } //求两圆相交的面积 double areacircle(circle v) { int rel=relationcircle(v); if (rel>=4) return 0.0; if (rel<=2) return min(area(),v.area()); double d=p.distance(v.p); double hf=(r+v.r+d)/2.0; double ss=2*sqrt(hf*(hf-r)*(hf-v.r)*(hf-d)); double a1=acos((r*r+d*d-v.r*v.r)/(2.0*r*d)); a1=a1*r*r; double a2=acos((v.r*v.r+d*d-r*r)/(2.0*v.r*d)); a2=a2*v.r*v.r; return a1+a2-ss; } //求圆和三角形 pab 的相交面积 double areatriangle(Point a,Point b) { if (sgn((p-a)^(p-b))==0) return 0.0; Point q[5]; int len=0; q[len++]=a; Line l(a,b); Point p1,p2; if (pointcrossline(l,q[1],q[2])==2) { if (sgn((a-q[1])*(b-q[1]))<0) q[len++]=q[1]; if (sgn((a-q[2])*(b-q[2]))<0) q[len++]=q[2]; } q[len++]=b; if (len==4 && sgn((q[0]-q[1])*(q[2]-q[1]))>0) swap(q[1],q[2]); double res=0; for (int i=0; i<len-1; i++) { if (relation(q[i])==0||relation(q[i+1])==0) { double arg=p.rad(q[i],q[i+1]); res+=r*r*arg/2.0; } else { res+=fabs((q[i]-p)^(q[i+1]-p))/2.0; } } return res; } }; bool check(double x) { if(abs(round(x) - x) <= eps) return true; else return false; } void solve() { int x1,y1,x2,y2;cin >> x1 >> y1 >> x2 >> y2; double r = sqrt(5.0); Point a = Point{x1,y1}; Point b = Point(x2,y2); circle c1 = circle(a,r); circle c2 = circle(b,r); Point f1,f2; int tmp = c1.pointcrosscircle(c2,f1,f2); if(tmp == 0) printf("No\n"); else if(tmp == 1) { if(check(f1.x) && check(f1.y)) printf("Yes\n"); else printf("No\n"); } else { if((check(f1.x) && check(f1.y)) || (check(f2.x) && check(f2.y))) printf("Yes\n"); else printf("No\n"); } } int main() { // int _; // for(scanf("%d",&_);_;_--) { solve(); //} // system("pause"); return 0; }
D:这题看错题意了。
是在A~B,C~D之间取。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 205; const int M = 1e7 + 5; const LL Mod = 998244353; #define rep(at,am,as) for(int at = am;at <= as;++at) #define INF 1e18 #define dbg(ax) cout << "now this num is " << ax << endl; inline long long ADD(long long x,long long y) { if(x + y < 0) return ((x + y) % Mod + Mod) % Mod; return (x + y) % Mod; } inline long long MUL(long long x,long long y) { if(x * y < 0) return ((x * y) % Mod + Mod) % Mod; return x * y % Mod; } inline long long DEC(long long x,long long y) { if(x - y < 0) return (x - y + Mod) % Mod; return (x - y) % Mod; } int prime[N],tot = 0; bool vis[N]; void init() { rep(i,2,N - 1) { if(!vis[i]) prime[++tot] = i; for(int j = 1;j <= tot && prime[j] * i < N;++j) { vis[prime[j] * i] = 1; if(i % prime[j] == 0) break; } } } void solve() { init(); int a,b,c,d;cin >> a >> b >> c >> d; rep(i,a,b) { bool f = 0; rep(j,c,d) { if(vis[i + j] == 0) f = 1; } if(!f) {printf("Takahashi\n");return;} } printf("Aoki\n"); } int main() { // int _; // for(scanf("%d",&_);_;_--) { solve(); //} // system("pause"); return 0; }
E:因为K最大只有20,维护了一个只有最大为20的小顶堆。
然后暴力求一下即可。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 1e5 + 5; const int M = 1e7 + 5; const LL Mod = 998244353; #define rep(at,am,as) for(int at = am;at <= as;++at) #define INF 1e18 #define dbg(ax) cout << "now this num is " << ax << endl; inline long long ADD(long long x,long long y) { if(x + y < 0) return ((x + y) % Mod + Mod) % Mod; return (x + y) % Mod; } inline long long MUL(long long x,long long y) { if(x * y < 0) return ((x * y) % Mod + Mod) % Mod; return x * y % Mod; } inline long long DEC(long long x,long long y) { if(x - y < 0) return (x - y + Mod) % Mod; return (x - y) % Mod; } int n,q,x[N]; vector<int> G[N]; vector<int> mx[N]; void dfs(int u,int fa) { priority_queue<int,vector<int>,greater<int> > Q; Q.push(x[u]); for(auto v : G[u]) { if(v == fa) continue; dfs(v,u); for(auto v : mx[v]) { Q.push(v); while(Q.size() > 20) Q.pop(); } } while(!Q.empty()) { mx[u].push_back(Q.top()); Q.pop(); } } void solve() { scanf("%d %d",&n,&q); rep(i,1,n) scanf("%d",&x[i]); rep(i,1,n - 1) { int x,y;scanf("%d %d",&x,&y); G[x].push_back(y); G[y].push_back(x); } dfs(1,0); rep(i,1,n) { sort(mx[i].begin(),mx[i].end(),greater<int>()); } rep(i,1,q) { int v,k;scanf("%d %d",&v,&k); printf("%d\n",mx[v][k - 1]); } } int main() { // int _; // for(scanf("%d",&_);_;_--) { solve(); //} // system("pause"); return 0; }
F:首先先将所有连通块都连通在一起,然后再不断取两个没连通的加边即可。
主要是第一部分,将所有连通块按可连出的边的数量排序,从大的向之后连。这样能保证不会有小的连通块和小的连通块练完导致不能和别的连了。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 2e5 + 5; const int M = 1e7 + 5; const LL Mod = 998244353; #define rep(at,am,as) for(int at = am;at <= as;++at) #define INF 1e18 #define dbg(ax) cout << "now this num is " << ax << endl; inline long long ADD(long long x,long long y) { if(x + y < 0) return ((x + y) % Mod + Mod) % Mod; return (x + y) % Mod; } inline long long MUL(long long x,long long y) { if(x * y < 0) return ((x * y) % Mod + Mod) % Mod; return x * y % Mod; } inline long long DEC(long long x,long long y) { if(x - y < 0) return (x - y + Mod) % Mod; return (x - y) % Mod; } int n,m,d[N],in[N],dis[N],tot = 0; vector<int> vec[N],G[N]; bool vis[N]; void dfs(int x,int clr) { vec[clr].push_back(x); vis[x] = 1; for(auto v : G[x]) { if(!vis[v]) dfs(v,clr); } } vector<pii> ans; LL sum[N]; vector<int> id; void solve() { cin >> n >> m; rep(i,1,n) cin >> d[i]; rep(i,1,m) { int x,y;cin >> x >> y; in[x]++,in[y]++; G[x].push_back(y); G[y].push_back(x); } rep(i,1,n) { if(!vis[i]) { ++tot; dfs(i,tot); } } LL tmp = 0; rep(i,1,n) { dis[i] = d[i] - in[i],tmp += dis[i]; if(dis[i] < 0) {printf("-1\n");return;} } int ned = n - m - 1; if(tmp / 2 != ned) {printf("-1\n");return;} rep(i,1,tot) { sort(vec[i].begin(),vec[i].end(),[](int x,int y) { return dis[x] > dis[y]; }); for(auto v : vec[i]) sum[i] += dis[v]; id.push_back(i); } sort(id.begin(),id.end(),[](int x,int y){ return sum[x] > sum[y]; }); queue<int> Q; for(auto v : vec[id[0]]) { if(dis[v] > 0) Q.push(v); } rep(i,1,tot - 1) { bool f = 0; int to = id[i]; for(auto v : vec[to]) { if(dis[v] > 0 && f == 0) { if(!Q.empty()) { int k = Q.front(); dis[k]--,dis[v]--; ans.push_back(pii{k,v}); if(dis[k] == 0) Q.pop(); f = 1; } } } if(f == 0) {printf("-1\n");return;} for(auto v : vec[to]) { if(dis[v] > 0) Q.push(v); } } if(Q.size() == 0) { for(auto v : ans) printf("%d %d\n",v.first,v.second); return; } int v = Q.front();Q.pop(); while(!Q.empty()) { ans.push_back(pii{v,Q.front()}); dis[Q.front()]--; dis[v]--; if(dis[Q.front()] == 0) { Q.pop(); if(Q.size() == 0) break; } if(dis[v] == 0) v = Q.front(),Q.pop(); } if(dis[v] == 0) { for(auto v : ans) printf("%d %d\n",v.first,v.second); } else printf("-1\n"); } int main() { // int _; // for(scanf("%d",&_);_;_--) { solve(); //} // system("pause"); return 0; }
G:其实是个挺板子的题:求网络流上的最小割。
自己对自己连c[i]容量的边即可。
然后后面最小割的割集求法:我们从源点开始dfs,如果边的容量为0,那么就是割边,那么就不能再走了。
那么,割点就存在一半在源点的那部分图,另一半在汇点那部分图。
即vis[i] ^ vis[i + n] = 1.
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 1e3 + 5; const int M = 1e6 + 5; const LL Mod = 998244353; #define rep(at,am,as) for(int at = am;at <= as;++at) #define INF 1e18 #define int long long #define dbg(ax) cout << "now this num is " << ax << endl; inline long long ADD(long long x,long long y) { if(x + y < 0) return ((x + y) % Mod + Mod) % Mod; return (x + y) % Mod; } inline long long MUL(long long x,long long y) { if(x * y < 0) return ((x * y) % Mod + Mod) % Mod; return x * y % Mod; } inline long long DEC(long long x,long long y) { if(x - y < 0) return (x - y + Mod) % Mod; return (x - y) % Mod; } int n,m,s,t,cnt = -1; int head[N],dep[N],cur[N],c[N]; struct Node{int to;LL dis;int next;}e[M << 2]; inline void add(int u,int v,LL w) { e[++cnt].to = v,e[cnt].dis = w,e[cnt].next = head[u],head[u] = cnt; e[++cnt].to = u,e[cnt].dis = 0,e[cnt].next = head[v],head[v] = cnt; } inline void init() { memset(head,-1,sizeof(head)); cnt = -1; } bool bfs() {//分层 queue<int> Q; memset(dep,-1,sizeof(dep)); dep[s] = 0; Q.push(s); while(!Q.empty()) { int u = Q.front(); Q.pop(); for(int i=head[u];i!=-1;i=e[i].next) { int y = e[i].to,d = e[i].dis; if(dep[y] == -1 && d > 0) { dep[y] = dep[u]+1; Q.push(y); } } } return dep[t] != -1; } int dfs(int u,LL flow) { int nowflow = 0,k; if(u == t) return flow; for(int i=head[u];i!=-1;i=e[i].next) { cur[u] = i;//当前弧优化 int y = e[i].to,d = e[i].dis; if((dep[y] == dep[u] + 1) && d > 0) { if(k = dfs(y,min(flow-nowflow,d))) { e[i].dis -= k; e[i^1].dis += k; nowflow += k; if(nowflow == flow) break; } } } if(nowflow == 0) dep[u] = -1;//炸点优化 return nowflow; } int Dinic() { int ans = 0; while(bfs()) { for(int i = 1;i <= t;++i) cur[i] = head[i]; ans += dfs(s,INF); } return ans; } /* point [1 ~ n] ,[n + 1,2 * n] */ bool vis[N]; void dfs1(int u) { vis[u] = 1; for(int i = head[u];i != -1;i = e[i].next) { int v = e[i].to; if(vis[v] || e[i].dis == 0) continue; dfs1(v); } } void solve() { init(); cin >> n >> m; rep(i,1,m) { int x,y;cin >> x >> y; add(x + n,y,INF); add(y + n,x,INF); } rep(i,1,n) cin >> c[i]; rep(i,1,n) { if(i == 1 || i == n) add(i,i + n,INF); else add(i,i + n,c[i]); } s = 2 * n + 1,t = 2 * n + 2; add(s,1,INF); add(2 * n,t,INF); LL ans = Dinic(); printf("%lld\n",ans); vector<int> vec; dfs1(2 * n + 1); rep(i,2,n - 1) { if(vis[i] ^ vis[i + n]) vec.push_back(i); } printf("%lld\n",vec.size()); rep(i,0,vec.size() - 1) printf("%lld%c",vec[i],i == vec.size() - 1 ? '\n' : ' '); } signed main() { // int _; // for(scanf("%d",&_);_;_--) { solve(); //} // system("pause"); return 0; }