2012-C18-team5
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
E 题数论,不会做,我上机乱搞了一阵是 WA,没有办法只好放弃去搞其他题。后来题目做得没什么可做的时候,学姐写了个对拍程序,很快就就找到 WA 的地方了,不过还是不会做
比赛快结束的时候,再推了一下式子,发现似乎能用 exgcd 来求,结果时间比较紧,抄 exgcd 模板时抄错了...
其他题还好,没有多大的问题
顺便想起前几场比赛时的情况,建议学长学姐们在讨论题目看看数据范围,能先想 DP 时就不要去想贪心,尤其不知道贪心对不对的时候(此时一般想的贪心都是错的,比如天津的 1006 那题)
by 猛犸也钻地
附:I 题代码,处理直线相交时,需注意考虑重合的情况,我在这个地方 WA 了 1 小时才发现
{{{
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <utility>
#include <cassert>
#include <algorithm>
using namespace std;
using namespace rel_ops;
typedef double NUM;
const NUM EPS = 1e-12, MAGIC = 2.71828e18;
inline NUM sqr(NUM a){return a*a;}
inline NUM cmp(NUM a, NUM b){
return fabs(a-b)>=EPS+fabs(a)*EPS?a-b:0;
}
struct VEC{NUM x,y;} NOVEC = {MAGIC,MAGIC};
struct RAY{VEC u,v;} NORAY = {NOVEC,NOVEC};
inline NUM sqr(const VEC& a){return sqr(a.x)+sqr(a.y);}
inline double abs(const VEC& a){return sqrt(sqr(a));}
inline NUM cmp(const VEC& a, const VEC& b){
NUM at=cmp(a.x,b.x);
return !at?cmp(a.y,b.y):at;
}
inline VEC operator +(const VEC& a, const VEC& b)
{return (VEC){a.x+b.x,a.y+b.y};}
inline VEC operator -(const VEC& a, const VEC& b)
{return (VEC){a.x-b.x,a.y-b.y};}
inline NUM operator *(const VEC& a, const VEC& b)
{return a.x*b.y-a.y*b.x;}
inline NUM operator %(const VEC& a, const VEC& b)
{return a.x*b.x+a.y*b.y;}
inline VEC operator -(const VEC& a){return (VEC){-a.x,-a.y};}
inline VEC operator ~(const VEC& a){return (VEC){-a.y,+a.x};}
inline VEC operator *(NUM u, const VEC& a){return (VEC){u*a.x,u*a.y};}
inline VEC operator *(const VEC& a, NUM u){return (VEC){a.x*u,a.y*u};}
inline VEC operator /(const VEC& a, NUM u){return (VEC){a.x/u,a.y/u};}
inline VEC operator /(const VEC& a, const VEC& b){return a%b/sqr(b)*b;}
inline bool operator ==(const VEC& a, const VEC& b){return !cmp(a,b);}
inline bool operator <(const VEC& a, const VEC& b){return cmp(a,b)<0;}
NUM cmp_side(const VEC& a, const VEC& b){return cmp(a.x*b.y,+a.y*b.x);}
NUM cmp_axis(const VEC& a, const VEC& b){return cmp(a.x*b.x,-a.y*b.y);}
VEC cross(const RAY& a, const RAY& b){
VEC s=a.u-a.v,t=b.u-b.v;
NUM at=cmp_side(s,t);
if(!at) return NOVEC;
return a.u+(b.u-a.u)*t/at*s;
}
bool seg_range(const VEC& p, const RAY& l){
return cmp_axis(p-l.u,p-l.v)<=0;
}
typedef pair<int,int> PII;
typedef pair<double,int> PDI;
typedef vector<PII> VP;
int x[100005],y[100005];
vector<VEC> dot[100005],all;
vector<PDI> e[2100005];
double l[2100005];
double dijkstra(int s, int t){
priority_queue<PDI> q;
q.push(PDI(l[s]=0,s));
while(q.size()){
int x=q.top().second;
double now=-q.top().first;
q.pop();
if(cmp(l[x],now)) continue;
if(x==t) break;
for(size_t i=0;i<e[x].size();i++){
int y=e[x][i].second;
double w=e[x][i].first;
if(cmp(w+l[x],l[y])<0){
l[y]=l[x]+w;
q.push(PDI(-l[y],y));
}
}
}
return l[t];
}
int main(){
int cs,n;
scanf("%d",&cs);
while(cs--){
scanf("%d",&n);
map<int,VP> u;
for(int i=0;i<n;i++){
scanf("%d%d",x+i,y+i);
u[x[i]].push_back(PII(y[i],i));
}
all.push_back((VEC){x[0],y[0]});
u[-10000100];
u[+10000100];
for(map<int,VP>::iterator t=u.begin();t!=u.end();++t)
sort(t->second.begin(),t->second.end());
for(int i=0;i+1<n;i++){
vector<int> c;
for(map<int,VP>::iterator t=u.lower_bound(x[i]-43);t->first<=x[i]+43;++t){
vector<PII>& r=t->second;
vector<PII>::iterator o=lower_bound(r.begin(),r.end(),PII(y[i]-43,0));
while(o!=r.end() && o->first<=y[i]+43){
if(o->second<i){
c.push_back(o->second);
c.push_back(o->second-1);
}else if(o->second==i){
c.push_back(o->second-1);
}
o++;
}
}
sort(c.begin(),c.end());
c.erase(unique(c.begin(),c.end()),c.end());
RAY l={{x[i],y[i]},{x[i+1],y[i+1]}};
dot[i].push_back(l.u);
dot[i].push_back(l.v);
all.push_back(l.v);
for(size_t o=0;o<c.size();o++){
int j=c[o];
if(j<0) continue;
RAY g={{x[j],y[j]},{x[j+1],y[j+1]}};
VEC r=cross(g,l);
if(r==NOVEC){
if(cmp_side(g.u-l.u,l.v-l.u)
|| cmp_side(l.u-g.u,g.v-g.u)) continue;
if(seg_range(g.u,l)) dot[i].push_back(g.u);
if(seg_range(g.v,l)) dot[i].push_back(g.v);
if(seg_range(l.u,g)) dot[j].push_back(l.u);
if(seg_range(l.v,g)) dot[j].push_back(l.v);
}else if(seg_range(r,g) && seg_range(r,l)){
dot[i].push_back(r);
dot[j].push_back(r);
all.push_back(r);
}
}
}
sort(all.begin(),all.end());
all.erase(unique(all.begin(),all.end()),all.end());
for(int i=0;i+1<n;i++){
sort(dot[i].begin(),dot[i].end());
dot[i].erase(unique(dot[i].begin(),dot[i].end()),dot[i].end());
int x=lower_bound(all.begin(),all.end(),dot[i][0])-all.begin(),y;
for(size_t j=1;j<dot[i].size();j++,x=y){
y=lower_bound(all.begin(),all.end(),dot[i][j])-all.begin();
double l=abs(dot[i][j]-dot[i][j-1]);
e[x].push_back(PDI(l,y));
e[y].push_back(PDI(l,x));
}
dot[i].clear();
}
int s=lower_bound(all.begin(),all.end(),(VEC){x[0],y[0]})-all.begin();
int t=lower_bound(all.begin(),all.end(),(VEC){x[n-1],y[n-1]})-all.begin();
for(size_t i=0;i<all.size();i++) l[i]=1e20;
double ans=dijkstra(s,t);
printf("%.0f\n",fabs(ans));
for(size_t i=0;i<all.size();i++) e[i].clear();
all.clear();
}
}
}}}
E 题数论,不会做,我上机乱搞了一阵是 WA,没有办法只好放弃去搞其他题。后来题目做得没什么可做的时候,学姐写了个对拍程序,很快就就找到 WA 的地方了,不过还是不会做
比赛快结束的时候,再推了一下式子,发现似乎能用 exgcd 来求,结果时间比较紧,抄 exgcd 模板时抄错了...
其他题还好,没有多大的问题
顺便想起前几场比赛时的情况,建议学长学姐们在讨论题目看看数据范围,能先想 DP 时就不要去想贪心,尤其不知道贪心对不对的时候(此时一般想的贪心都是错的,比如天津的 1006 那题)
by 猛犸也钻地
附:I 题代码,处理直线相交时,需注意考虑重合的情况,我在这个地方 WA 了 1 小时才发现
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <utility>
#include <cassert>
#include <algorithm>
using namespace std;
using namespace rel_ops;
typedef double NUM;
const NUM EPS = 1e-12, MAGIC = 2.71828e18;
inline NUM sqr(NUM a){return a*a;}
inline NUM cmp(NUM a, NUM b){
return fabs(a-b)>=EPS+fabs(a)*EPS?a-b:0;
}
struct VEC{NUM x,y;} NOVEC = {MAGIC,MAGIC};
struct RAY{VEC u,v;} NORAY = {NOVEC,NOVEC};
inline NUM sqr(const VEC& a){return sqr(a.x)+sqr(a.y);}
inline double abs(const VEC& a){return sqrt(sqr(a));}
inline NUM cmp(const VEC& a, const VEC& b){
NUM at=cmp(a.x,b.x);
return !at?cmp(a.y,b.y):at;
}
inline VEC operator +(const VEC& a, const VEC& b)
{return (VEC){a.x+b.x,a.y+b.y};}
inline VEC operator -(const VEC& a, const VEC& b)
{return (VEC){a.x-b.x,a.y-b.y};}
inline NUM operator *(const VEC& a, const VEC& b)
{return a.x*b.y-a.y*b.x;}
inline NUM operator %(const VEC& a, const VEC& b)
{return a.x*b.x+a.y*b.y;}
inline VEC operator -(const VEC& a){return (VEC){-a.x,-a.y};}
inline VEC operator ~(const VEC& a){return (VEC){-a.y,+a.x};}
inline VEC operator *(NUM u, const VEC& a){return (VEC){u*a.x,u*a.y};}
inline VEC operator *(const VEC& a, NUM u){return (VEC){a.x*u,a.y*u};}
inline VEC operator /(const VEC& a, NUM u){return (VEC){a.x/u,a.y/u};}
inline VEC operator /(const VEC& a, const VEC& b){return a%b/sqr(b)*b;}
inline bool operator ==(const VEC& a, const VEC& b){return !cmp(a,b);}
inline bool operator <(const VEC& a, const VEC& b){return cmp(a,b)<0;}
NUM cmp_side(const VEC& a, const VEC& b){return cmp(a.x*b.y,+a.y*b.x);}
NUM cmp_axis(const VEC& a, const VEC& b){return cmp(a.x*b.x,-a.y*b.y);}
VEC cross(const RAY& a, const RAY& b){
VEC s=a.u-a.v,t=b.u-b.v;
NUM at=cmp_side(s,t);
if(!at) return NOVEC;
return a.u+(b.u-a.u)*t/at*s;
}
bool seg_range(const VEC& p, const RAY& l){
return cmp_axis(p-l.u,p-l.v)<=0;
}
typedef pair<int,int> PII;
typedef pair<double,int> PDI;
typedef vector<PII> VP;
int x[100005],y[100005];
vector<VEC> dot[100005],all;
vector<PDI> e[2100005];
double l[2100005];
double dijkstra(int s, int t){
priority_queue<PDI> q;
q.push(PDI(l[s]=0,s));
while(q.size()){
int x=q.top().second;
double now=-q.top().first;
q.pop();
if(cmp(l[x],now)) continue;
if(x==t) break;
for(size_t i=0;i<e[x].size();i++){
int y=e[x][i].second;
double w=e[x][i].first;
if(cmp(w+l[x],l[y])<0){
l[y]=l[x]+w;
q.push(PDI(-l[y],y));
}
}
}
return l[t];
}
int main(){
int cs,n;
scanf("%d",&cs);
while(cs--){
scanf("%d",&n);
map<int,VP> u;
for(int i=0;i<n;i++){
scanf("%d%d",x+i,y+i);
u[x[i]].push_back(PII(y[i],i));
}
all.push_back((VEC){x[0],y[0]});
u[-10000100];
u[+10000100];
for(map<int,VP>::iterator t=u.begin();t!=u.end();++t)
sort(t->second.begin(),t->second.end());
for(int i=0;i+1<n;i++){
vector<int> c;
for(map<int,VP>::iterator t=u.lower_bound(x[i]-43);t->first<=x[i]+43;++t){
vector<PII>& r=t->second;
vector<PII>::iterator o=lower_bound(r.begin(),r.end(),PII(y[i]-43,0));
while(o!=r.end() && o->first<=y[i]+43){
if(o->second<i){
c.push_back(o->second);
c.push_back(o->second-1);
}else if(o->second==i){
c.push_back(o->second-1);
}
o++;
}
}
sort(c.begin(),c.end());
c.erase(unique(c.begin(),c.end()),c.end());
RAY l={{x[i],y[i]},{x[i+1],y[i+1]}};
dot[i].push_back(l.u);
dot[i].push_back(l.v);
all.push_back(l.v);
for(size_t o=0;o<c.size();o++){
int j=c[o];
if(j<0) continue;
RAY g={{x[j],y[j]},{x[j+1],y[j+1]}};
VEC r=cross(g,l);
if(r==NOVEC){
if(cmp_side(g.u-l.u,l.v-l.u)
|| cmp_side(l.u-g.u,g.v-g.u)) continue;
if(seg_range(g.u,l)) dot[i].push_back(g.u);
if(seg_range(g.v,l)) dot[i].push_back(g.v);
if(seg_range(l.u,g)) dot[j].push_back(l.u);
if(seg_range(l.v,g)) dot[j].push_back(l.v);
}else if(seg_range(r,g) && seg_range(r,l)){
dot[i].push_back(r);
dot[j].push_back(r);
all.push_back(r);
}
}
}
sort(all.begin(),all.end());
all.erase(unique(all.begin(),all.end()),all.end());
for(int i=0;i+1<n;i++){
sort(dot[i].begin(),dot[i].end());
dot[i].erase(unique(dot[i].begin(),dot[i].end()),dot[i].end());
int x=lower_bound(all.begin(),all.end(),dot[i][0])-all.begin(),y;
for(size_t j=1;j<dot[i].size();j++,x=y){
y=lower_bound(all.begin(),all.end(),dot[i][j])-all.begin();
double l=abs(dot[i][j]-dot[i][j-1]);
e[x].push_back(PDI(l,y));
e[y].push_back(PDI(l,x));
}
dot[i].clear();
}
int s=lower_bound(all.begin(),all.end(),(VEC){x[0],y[0]})-all.begin();
int t=lower_bound(all.begin(),all.end(),(VEC){x[n-1],y[n-1]})-all.begin();
for(size_t i=0;i<all.size();i++) l[i]=1e20;
double ans=dijkstra(s,t);
printf("%.0f\n",fabs(ans));
for(size_t i=0;i<all.size();i++) e[i].clear();
all.clear();
}
}
附加文件
- Contest 18 by way to answer.zip by oldjunyi