牛客网多校第三场

A:PACM Team

四维的01背包,注意一下所有代价都是0时的方案输出即可

#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

#define maxn 37

using namespace std;

int p[maxn],a[maxn],c[maxn],m[maxn],g[maxn];
int dp[maxn][maxn][maxn][maxn],use[maxn];
int n,P,A,C,M;

vector <int> mem;

int main(){
    scanf("%d",&n);
    int cnt=0;

    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d%d%d",&p[i],&a[i],&c[i],&m[i],&g[i]);
        if(p[i]==0&&a[i]==0&&c[i]==0&&m[i]==0)
        {
            mem.push_back(i);
            use[i]=1;
        }
    }
    scanf("%d%d%d%d",&P,&A,&C,&M);
    dp[0][0][0][0]=0;
    for(int i=1;i<=n;i++){
        if(use[i]==1) continue;
        for(int j=P;j>=0;j--)
            for(int k=A;k>=0;k--)
                for(int t=C;t>=0;t--)
                    for(int l=M;l>=0;l--)
                        if(j>=p[i] && k>=a[i] && t>=c[i] && l>=m[i]){
                            if(dp[j][k][t][l]<dp[j-p[i]][k-a[i]][t-c[i]][l-m[i]]+g[i]){
                                dp[j][k][t][l]=dp[j-p[i]][k-a[i]][t-c[i]][l-m[i]]+g[i];
                            }
                        }
    }
    int ans=0,l1=P,l2=A,l3=C,l4=M;
    for(int j=P;j>=0;j--)
            for(int k=A;k>=0;k--)
                for(int t=C;t>=0;t--)
                    for(int l=M;l>=0;l--)
                        if(dp[j][k][t][l]>=ans){
                            l1=j; l2=k; l3=t; l4=l;
                            ans=dp[j][k][t][l];
                        }

    while(1){
        int t=233;
        for(int i=1;i<=n;i++)
            if(!(p[i]==0 && a[i]==0 && c[i]==0 && m[i]==0) && !use[i] && l1>=p[i] && l2>=a[i] && l3>=c[i] && l4>=m[i] && dp[l1][l2][l3][l4]==dp[l1-p[i]][l2-a[i]][l3-c[i]][l4-m[i]]+g[i]){
                use[i]=1; t=i; break;
            }
        if(t==233) break;
        mem.push_back(t);
        l1-=p[t]; l2-=a[t]; l3-=c[t]; l4-=m[t];
    }
    printf("%d\n",mem.size());
    for(int i=0;i<mem.size();i++)
        printf("%d ",mem[i]-1);
    return 0;
}
View Code

C:Shuffle Cards

 Splay基本操作,可以把目标区间[l,r]删掉,再提到开头,也可以在[l,r],[1,r-l+1],[r-l+2,r]打三次翻转标记

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<algorithm>
  5 
  6 #define maxn 100000+5
  7 
  8 using namespace std;
  9 
 10 struct Splay_Tree{
 11     int ch[2];
 12     int sz,key;
 13 }tr[maxn<<1];
 14 
 15 int a[maxn];
 16 int n,m,cnt,root;
 17 
 18 inline int in(){
 19     int x=0,f=1;
 20     char ch=getchar();
 21     while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
 22     while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
 23     return x*f;
 24 }
 25 
 26 inline void Update(int k){
 27     tr[k].sz=tr[tr[k].ch[0]].sz+tr[tr[k].ch[1]].sz+1;
 28 }
 29 
 30 inline void Rotate(int &k,int d){
 31     int t=tr[k].ch[d^1];
 32     tr[k].ch[d^1]=tr[t].ch[d]; tr[t].ch[d]=k;
 33     Update(k); Update(t); k=t;
 34 }
 35 
 36 void Splay(int &k,int x){
 37     int d1=(tr[tr[k].ch[0]].sz<x?1:0),t=tr[k].ch[d1];
 38     if(d1==1) x-=tr[tr[k].ch[0]].sz+1;
 39     if(x){
 40         int d2=(tr[tr[t].ch[0]].sz<x?1:0);
 41         if(d2==1) x-=tr[tr[t].ch[0]].sz+1;
 42         if(x){
 43             Splay(tr[t].ch[d2],x);
 44             if(d1==d2) Rotate(k,d1^1);
 45             else Rotate(tr[k].ch[d1],d1);
 46         }
 47         Rotate(k,d1^1);
 48     }
 49     Update(k);
 50 }
 51 
 52 void dfs(int x){
 53     if(tr[x].ch[0]) dfs(tr[x].ch[0]);
 54     if(tr[x].key>=1 && tr[x].key<=n) printf("%d ",tr[x].key);
 55     if(tr[x].ch[1]) dfs(tr[x].ch[1]);
 56 }
 57 
 58 void Insert(int x,char val){
 59     Splay(root,x+1); Splay(tr[root].ch[1],x+1-tr[tr[root].ch[0]].sz);
 60     //本应为Splay(tr[root].r,x+2-(tr[tr[root].ch[0]].sz+1));
 61     int k=++cnt;
 62     tr[k].key=val; tr[k].ch[0]=tr[k].ch[1]=0;
 63     tr[tr[root].ch[1]].ch[0]=k;
 64     Update(k); Update(tr[root].ch[1]); Update(root);
 65 }
 66 
 67 void Delete(int l,int r){
 68     Splay(root,l); 
 69     Splay(tr[root].ch[1],1+r-tr[tr[root].ch[0]].sz);
 70     int k=tr[tr[root].ch[1]].ch[0];
 71     tr[tr[root].ch[1]].ch[0]=0;
 72     Update(tr[root].ch[1]); Update(root); 
 73     Splay(root,1); Splay(tr[root].ch[1],1-tr[tr[root].ch[0]].sz);
 74     tr[tr[root].ch[1]].ch[0]=k;
 75     Update(k); Update(tr[root].ch[1]); Update(root);
 76    
 77     
 78 }
 79 
 80 void Build(int l,int r,int &k){
 81     if(l>r) return;
 82     if(l==r){
 83         k=++cnt; tr[k].ch[0]=tr[k].ch[1]=0;
 84         tr[k].key=a[l];
 85         tr[k].sz=1;
 86         return;
 87     }
 88     int mid=(l+r)>>1; k=++cnt;
 89     Build(l,mid-1,tr[k].ch[0]);
 90     Build(mid+1,r,tr[k].ch[1]);
 91     tr[k].key=a[mid];
 92     Update(k);
 93 }
 94 
 95 int main(){
 96     n=in(); m=in();
 97     for(int i=1;i<=n;i++) a[i]=i;
 98     Build(0,n+1,root); 
 99 //    dfs(root); puts("");
100     for(int i=1;i<=m;i++){
101         int l,r,x;
102         l=in(); x=in();
103         r=l+x-1;
104         Delete(l,r);
105     }
106     dfs(root);
107     return 0;
108 }
View Code

 

E:Sort String

先把串拼成二倍长,预处理整串hash值。然后遍历取n个字符的hash值,map一下看看有没有重复并且存到vector中,最后直接输出

然鹅被卡常了还是getchar快一点

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#include <string>
#include <map>
#include <unordered_map>
#define LSON l,m,x<<1
#define RSON m+1,r,x<<1|1
using namespace std;

const int MAX=2e6+5;
const unsigned long long base = 163;
char s[MAX];
unsigned long long p[MAX],hh[MAX];
unordered_map<unsigned long long,int> mp;
int cnt;
vector<int> L[MAX];

void init(){//处理hh值
    p[0] = 1;
    hh[0] = 0;
    int n = strlen(s + 1);
    for(int i = 1; i < MAX/2; i ++) p[i] =p[i-1] * base;
    for(int i = 1; i <= n; i ++) hh[i] = hh[i - 1] * base + (s[i] - 'a');
}

inline unsigned long long get(int l, int r){//取出g里l - r里面的字符串的hh值
    return hh[r] - hh[l - 1] * p[r - l + 1];
}

inline string read()//inline继续加快速度
{
    char ch=getchar();
    string st1="";
    while (!((ch>='a')&&(ch<='z')))//把前面没用的东西去掉,当然,ch在什么范围内可以依据需要修改
      ch=getchar();
    while ((ch>='a')&&(ch<='z'))
      st1+=ch,ch=getchar();
    return st1;//返回
}//在主程序内可以写st=read(),这样子要读的字符串就到了st内

int main(){
    int i,j; char ch;
    i=0;
    while((ch=getchar())!=EOF){
        s[++i]=ch;
    }
    if(s[i]=='\n') i--;
    int n=i;
    for(i=n+1;i<=2*n;i++)
        s[i]=s[i-n];
    init();
    for(i=1;i<=n;i++){
        unsigned long long h=get(i,i+n-1);
        if(!mp[h]){
            mp[h]=++cnt;
            L[cnt].push_back(i-1);
        }
        else
            L[mp[h]].push_back(i-1);
    }
    printf("%d\n",cnt);
    for(i=1;i<=cnt;i++){
        int size=L[i].size();
        printf("%d ",size);
        for(j=0;j<size;j++){
            printf("%d%c",L[i][j],j==size-1?'\n':' ');
        }
    }
    return 0;
}
View Code

F:Sum Of Digit

求十六进制串的SOD,发现有规律只和数字的和有关,需要统计区间内所有子串的SOD,遂用线段树维护每个区间内SOD=0-15方案的个数,向上更新的时候卷积就好。

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#include <string>
#include <map>
#include <ctime>
#define LSON l,m,x<<1
#define RSON m+1,r,x<<1|1
using namespace std;

const int MAX=1e5+5;
const int D=16;
const int mod=1e9+7;
struct node{
    long long v[D];
}xds[MAX*4];

int n,q;
char s[MAX];
int R[D][D];
long long num[D];

node operator + (const node &a,const node &b){
    node ret;
    for(int i=0;i<D;i++) ret.v[i]=0;
    for(int i=0;i<D;i++){
        for(int j=0;j<D;j++){
            if(a.v[i]&&b.v[j]){
                int val=(a.v[i]*b.v[j])%mod;
                int to=R[i][j];
                ret.v[to]=(ret.v[to]+val)%mod;
            }
        }
    }
    return ret;
}

int trans(char c){
    if(isdigit(c)) return c-'0';
    return c-'A'+10;
}

void pushup(int x){
    xds[x]=xds[x<<1]+xds[x<<1|1];
}

void js(int l,int r,int x) {
    int m=(l+r)/2;

    if(l==r){
        xds[x].v[0]++;
        xds[x].v[trans(s[l])]++;
        return;
    }
    js(LSON);
    js(RSON);
    pushup(x);
}

void xg(int pos,int val,int l,int r,int x){
    int m=(l+r)/2;
    
    if(l==r&&pos==l){
        for(int i=0;i<D;i++)
            xds[x].v[i]=0;
        xds[x].v[0]++;
        xds[x].v[val]++;
        return;
    }
    if(pos<=m) 
        xg(pos,val,LSON);
    else
        xg(pos,val,RSON);
    pushup(x);
}

node cx(int L,int R,int l,int r,int x){
    int m = (l + r) / 2;
    
    if(L==l&&R==r)
        return xds[x];
    if(R<=m)
        return cx(L,R,LSON);
    if(L>m) 
        return cx(L,R,RSON);
    return cx(L,m,LSON)+cx(m+1,R,RSON);
}

long long query(int l,int r){
    long long ans=0;
    node tmp=cx(l,r,1,n,1);
    for(int i=0;i<D;i++)
        ans=(ans+(tmp.v[i]*num[i])%mod)%mod;
    return ans-1;
}

void init(void){
    for(int i=0;i<D;i++)
        for(int j=0;j<D;j++){
            int to=(i+j)%(D-1);
            if((i+j)!=0&&to==0) to=15;
            R[i][j]=to;
        }
    num[0]=1;
    for(int i=1;i<D;i++)
        num[i]=(num[i-1]*1021)%mod;
}

int main(){
    int i,j;
    
    init();
    scanf("%d%d",&n,&q);
    scanf("%s",s+1);
    js(1,n,1);
    while(q--){
        int op,l,r,pos;
        char c;
        scanf("%d",&op);
        if(op==1){
            scanf("%d %c",&pos,&c);
            xg(pos,trans(c),1,n,1);
        }
        else{
            scanf("%d%d",&l,&r);
            printf("%lld\n",query(l,r));
        }
    }
    
    return 0;
}
View Code

G: Coloring Tree

题目要求两个相同的染色最近距离为恰好为D,设函数f(D)为对某点距离D以内没有相同的颜色的点的方案数,即两个相同的染色最近距离大于等于D+1,则答案为f(D-1)-f(D)。

故按照bfs顺序计数,发现bfs过的节点里和当前节点距离小于D的点两两之间距离一定小于D。故每处理一个点x,在已经bfs过的点中搜索距离这个点D以内的点的个数,计为cnt,则x可染色的方案数为k-cnt,然后利用乘法原理计数。

#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

#define maxn 5000+5

using namespace std;

typedef long long LL;

const int mod=1e9+7;

struct Edge {
    int u,v,nxt;
    Edge() { }
    Edge(int a,int b,int c) {
        u=a,v=b,nxt=c;
    }
} e[maxn<<1];

int head[maxn],p[maxn],out[maxn];
int ind,n,k,d;

void addedge(int x,int y) {
    e[ind]=Edge(x,y,head[x]),head[x]=ind++;
    e[ind]=Edge(y,x,head[y]),head[y]=ind++;
}

int qpow(int x,int b) {
    int base=x,res=1;
    while(b) {
        if(b&1) res=(LL)res*base%mod;
        base=(LL)base*base%mod;
        b>>=1;
    }
    return res;
}

int bfs(int x,int pa,int dep) {    
    if(dep==0) return 1;
    int res=1;
    for(int i=head[x];i!=-1;i=e[i].nxt)
        if(e[i].v!=pa && out[e[i].v]){
            res+=bfs(e[i].v,x,dep-1);
        }
    return res;
}

int f(int dis) {
    if(dis==0) return qpow(k,n);
    memset(p,0,sizeof(p));
    memset(out,0,sizeof(out));
    queue <int> q;
    q.push(1); p[1]=1;
    int res=1;
    while(!q.empty()) {
        int x=q.front(); q.pop();
        out[x]=1;
        int cnt=bfs(x,0,dis)-1;
        if(cnt>=k) return 0;
        res=(LL)res*(k-cnt)%mod;
        for(int i=head[x];i!=-1;i=e[i].nxt)
            if(!p[e[i].v]){
                p[e[i].v]=1;
                q.push(e[i].v);
            }
    }
    return res;
}

int main() {
    memset(head,-1,sizeof(head));
    scanf("%d%d%d",&n,&k,&d);
    for(int i=1; i<n; i++) {
        int x,y;
        scanf("%d%d",&x,&y);
        addedge(x,y);
    }
    printf("%d",((f(d-1)-f(d))%mod+mod)%mod);
    return 0;
}
View Code

 

H:Diff-prime Pairs

随便推推公式就好,发现和小于n/num的质数数量有关,求一求质数数量的前缀和

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#include <string>
#include <map>
using namespace std;

int pri[6000010], cnt;
bool flag[10000010];
long long sum[10000010];

void init()
{
    cnt=0;
    for(int i = 2; i <= 10000000; i ++)
    {
        if(!flag[i])
        {
            pri[cnt ++] = i;
            flag[i] = 1;
        }
        for(int j = 0; j < cnt && i * pri[j] <= 10000000; j ++)
        {
            flag[i * pri[j]] = 1;
            if(i % pri[j] == 0)
            {
                break;
            }
        }
    }
}

int main()
{
    int i;
    init();
    for(i=0;i<cnt;i++) sum[pri[i]]++;
    for(i=0;i<=10000000;i++) sum[i]+=sum[i-1];
    int n;
    scanf("%d",&n);
    long long ans=0;
    for(i=1;i<=n;i++)
    {
        ans+=sum[n/i]*(sum[n/i]-1);
    }
    printf("%lld\n",ans);
    return 0;
}
View Code

 

I:Expected Size of Random Convex Hull

本地用随机数模拟打表

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#include <string>
#include <map>
#include <ctime>
#define LSON l,m,x<<1
#define RSON m+1,r,x<<1|1
#define RAND_MAX 80000
using namespace std;

const int MAX=30000+5;

//1.1 Point定义 
const double eps=1e-8; 
const double PI=acos(-1.0); 
int sgn(double x) 
{
    if(fabs(x)<eps)return 0;
    if(x < 0)return -1;
    else return 1;
}
struct Point
{
    double x,y;
    Point(){}                                    //默认构造器(),如果没有自定义构造器,则编译器会自动生成默认构造器 
    Point(double _x,double _y)    //自定义构造器 
    {
        x=_x;y=_y;
    }
    /*
        Point(double _x,double _y) : x(_x), y(_y)    //自定义构造器版本2,效果同上,但效率更高 
    {
    }
    */
    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;
    }
    bool operator < (const Point &b)const
    {
        if(x==b.x) return y<b.y;
        return x<b.x;
    }
    void transXY(double B)//绕原点旋转角度B(弧度值),后x,y的变化 
    {
        double tx=x,ty=y;
        x=tx*cos(B)-ty*sin(B);
        y=tx*sin(B)+ty*cos(B);
    }
};

//输入点数组p,个数为n,输出点数组ch。返回凸包顶点数
//输入不能有重复点。函数执行完之后输入点的顺序被破坏
//如果不希望在凸包的边上有输入点,把两个<=改为<
//在精度要求高时建议用cmp比较

int ConvexHull(Point* p,int n,Point *ch)
{
    sort(p,p+n); //先比较x坐标,再比较y坐标
    int m=0;
    for(int i=0;i<n;i++)
    {
        while(m > 1 && ((ch[m-1]-ch[m-2])^(p[i]-ch[m-2])) <= 0) m--;
        ch[m++] = p[i];
    }
    int k = m;
    for(int i = n-2; i >= 0; i--)
    {
        while(m > k && ((ch[m-1]-ch[m-2])^(p[i]-ch[m-2])) <= 0) m--;
        ch[m++] = p[i];
    }
    if(n > 1) m--;
    return m;
}

int m=1e7,n;
Point p[MAX],ch[MAX];
double ans;
long long sum;

int Rand(int l,int r){
    return (((long long)rand())*rand()%(r-l+1)+l);
}

int main(){
    int i,j;
    
    srand(time(0));
    printf("%d\n",RAND_MAX);
    for(n=4;n<=10;n++){
        sum=0;
        for(j=0;j<m;j++){
            //cout<<j<<endl;
            for(i=0;i<n;i++){
                p[i].x=rand();
                p[i].y=rand();
                if(p[i].x>p[i].y) swap(p[i].x,p[i].y);
            }
            sum+=ConvexHull(p,n,ch);
        }
        printf("%lf,",(double)sum/m);
    }
    
    return 0;
}

//double ans[100]={0,0,0,3.000000,3.000000,4.000000,4.000000,5.000000,6.000000,6.000000,6.000000};

//int main(){
//    int n;
//    int a,b,c,x,y,z;
//    scanf("%d%d%d%d%d%d%d",&a,&b,&c,&x,&y,&z,&n);
//    printf("%lf\n",ans[n]);
//    
//    return 0;
//}
View Code

J:Distance to Work

二分圆的大小,用多边形与圆的面积交的模板进行检查

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cmath>
  4 #include <vector>
  5 #include <algorithm>
  6  
  7 using namespace std;
  8 const double pi = 4 * atan(1);
  9 const double eps = 1e-10;
 10  
 11 inline int dcmp (double x) { if (fabs(x) < eps) return 0; else return x < 0 ? -1 : 1; }
 12 inline double getDistance (double x, double y) { return sqrt(x * x + y * y); }
 13  
 14 struct Point {
 15     double x, y;
 16     Point (double x = 0, double y = 0): x(x), y(y) {}
 17     void read () { scanf("%lf%lf", &x, &y); }
 18     void write () { printf("%lf %lf", x, y); }
 19  
 20     bool operator == (const Point& u) const { return dcmp(x - u.x) == 0 && dcmp(y - u.y) == 0; }
 21     bool operator != (const Point& u) const { return !(*this == u); }
 22     bool operator < (const Point& u) const { return x < u.x || (x == u.x && y < u.y); }
 23     bool operator > (const Point& u) const { return u < *this; }
 24     bool operator <= (const Point& u) const { return *this < u || *this == u; }
 25     bool operator >= (const Point& u) const { return *this > u || *this == u; }
 26     Point operator + (const Point& u) { return Point(x + u.x, y + u.y); }
 27     Point operator - (const Point& u) { return Point(x - u.x, y - u.y); }
 28     Point operator * (const double u) { return Point(x * u, y * u); }
 29     Point operator / (const double u) { return Point(x / u, y / u); }
 30     double operator * (const Point& u) { return x*u.y - y*u.x; }
 31 };
 32  
 33 typedef Point Vector;
 34  
 35 struct Line {
 36     double a, b, c;
 37     Line (double a = 0, double b = 0, double c = 0): a(a), b(b), c(c) {}
 38 };
 39  
 40 struct Circle {
 41     Point o;
 42     double r;
 43     Circle () {}
 44     Circle (Point o, double r = 0): o(o), r(r) {}
 45     void read () { o.read(), scanf("%lf", &r); }
 46     Point point(double rad) { return Point(o.x + cos(rad)*r, o.y + sin(rad)*r); }
 47     double getArea (double rad) { return rad * r * r / 2; }
 48 };
 49  
 50  
 51 namespace Punctual {
 52     double getDistance (Point a, Point b) { double x=a.x-b.x, y=a.y-b.y; return sqrt(x*x + y*y); }
 53 };
 54  
 55 namespace Vectorial {
 56     /* 点积: 两向量长度的乘积再乘上它们夹角的余弦, 夹角大于90度时点积为负 */
 57     double getDot (Vector a, Vector b) { return a.x * b.x + a.y * b.y; }
 58  
 59     /* 叉积: 叉积等于两向量组成的三角形有向面积的两倍, cross(v, w) = -cross(w, v) */
 60     double getCross (Vector a, Vector b) { return a.x * b.y - a.y * b.x; }
 61  
 62     double getLength (Vector a) { return sqrt(getDot(a, a)); }
 63     double getPLength (Vector a) { return getDot(a, a); }
 64     double getAngle (Vector u) { return atan2(u.y, u.x); }
 65     double getAngle (Vector a, Vector b) { return acos(getDot(a, b) / getLength(a) / getLength(b)); }
 66     Vector rotate (Vector a, double rad) { return Vector(a.x*cos(rad)-a.y*sin(rad), a.x*sin(rad)+a.y*cos(rad)); }
 67     /* 单位法线 */
 68     Vector getNormal (Vector a) { double l = getLength(a); return Vector(-a.y/l, a.x/l); }
 69 };
 70  
 71 namespace Linear {
 72     using namespace Vectorial;
 73  
 74     Line getLine (double x1, double y1, double x2, double y2) { return Line(y2-y1, x1-x2, y1*(x2-x1)-x1*(y2-y1)); }
 75     Line getLine (double a, double b, Point u) { return Line(a, -b, u.y * b - u.x * a); }
 76  
 77     bool getIntersection (Line p, Line q, Point& o) {
 78         if (fabs(p.a * q.b - q.a * p.b) < eps)
 79             return false;
 80         o.x = (q.c * p.b - p.c * q.b) / (p.a * q.b - q.a * p.b);
 81         o.y = (q.c * p.a - p.c * q.a) / (p.b * q.a - q.b * p.a);
 82         return true;
 83     }
 84  
 85     /* 直线pv和直线qw的交点 */
 86     bool getIntersection (Point p, Vector v, Point q, Vector w, Point& o) {
 87         if (dcmp(getCross(v, w)) == 0) return false;
 88         Vector u = p - q;
 89         double k = getCross(w, u) / getCross(v, w);
 90         o = p + v * k;
 91         return true;
 92     }
 93  
 94     /* 点p到直线ab的距离 */
 95     double getDistanceToLine (Point p, Point a, Point b) { return fabs(getCross(b-a, p-a) / getLength(b-a)); }
 96     double getDistanceToSegment (Point p, Point a, Point b) {
 97         if (a == b) return getLength(p-a);
 98         Vector v1 = b - a, v2 = p - a, v3 = p - b;
 99         if (dcmp(getDot(v1, v2)) < 0) return getLength(v2);
100         else if (dcmp(getDot(v1, v3)) > 0) return getLength(v3);
101         else return fabs(getCross(v1, v2) / getLength(v1));
102     }
103  
104     /* 点p在直线ab上的投影 */
105     Point getPointToLine (Point p, Point a, Point b) { Vector v = b-a; return a+v*(getDot(v, p-a) / getDot(v,v)); }
106  
107     /* 判断线段是否存在交点 */
108     bool haveIntersection (Point a1, Point a2, Point b1, Point b2) {
109         double c1=getCross(a2-a1, b1-a1), c2=getCross(a2-a1, b2-a1), c3=getCross(b2-b1, a1-b1), c4=getCross(b2-b1,a2-b1);
110         return dcmp(c1)*dcmp(c2) < 0 && dcmp(c3)*dcmp(c4) < 0;
111     }
112  
113     /* 判断点是否在线段上 */
114     bool onSegment (Point p, Point a, Point b) { return dcmp(getCross(a-p, b-p)) == 0 && dcmp(getDot(a-p, b-p)) < 0; }
115 }
116  
117 namespace Triangular {
118     using namespace Vectorial;
119  
120     double getAngle (double a, double b, double c) { return acos((a*a+b*b-c*c) / (2*a*b)); }
121     double getArea (double a, double b, double c) { double s =(a+b+c)/2; return sqrt(s*(s-a)*(s-b)*(s-c)); }
122     double getArea (double a, double h) { return a * h / 2; }
123     double getArea (Point a, Point b, Point c) { return fabs(getCross(b - a, c - a)) / 2; }
124     double getDirArea (Point a, Point b, Point c) { return getCross(b - a, c - a) / 2; }
125 };
126  
127 namespace Polygonal {
128     using namespace Vectorial;
129     using namespace Linear;
130  
131     double getArea (Point* p, int n) {
132         double ret = 0;
133         for (int i = 1; i < n-1; i++)
134             ret += getCross(p[i]-p[0], p[i+1]-p[0]);
135         return fabs(ret)/2;
136     }
137  
138     /* 凸包 */
139     int getConvexHull (Point* p, int n, Point* ch) {
140         sort(p, p + n);
141         int m = 0;
142         for (int i = 0; i < n; i++) {
143             /* 可共线 */
144             //while (m > 1 && dcmp(getCross(ch[m-1]-ch[m-2], p[i]-ch[m-1])) < 0) m--;
145             while (m > 1 && dcmp(getCross(ch[m-1]-ch[m-2], p[i]-ch[m-1])) <= 0) m--;
146             ch[m++] = p[i];
147         }
148         int k = m;
149         for (int i = n-2; i >= 0; i--) {
150             /* 可共线 */
151             //while (m > k && dcmp(getCross(ch[m-1]-ch[m-2], p[i]-ch[m-2])) < 0) m--;
152             while (m > k && dcmp(getCross(ch[m-1]-ch[m-2], p[i]-ch[m-2])) <= 0) m--;
153             ch[m++] = p[i];
154         }
155         if (n > 1) m--;
156         return m;
157     }
158  
159     int isPointInPolygon (Point o, Point* p, int n) {
160         int wn = 0;
161         for (int i = 0; i < n; i++) {
162             int j = (i + 1) % n;
163             if (onSegment(o, p[i], p[j])) return 0; // 边界上
164             int k = dcmp(getCross(p[j] - p[i], o-p[i]));
165             int d1 = dcmp(p[i].y - o.y);
166             int d2 = dcmp(p[j].y - o.y);
167             if (k > 0 && d1 <= 0 && d2 > 0) wn++;
168             if (k < 0 && d2 <= 0 && d1 > 0) wn--;
169         }
170         return wn ? -1 : 1;
171     }
172 };
173  
174 namespace Circular {
175     using namespace Linear;
176     using namespace Vectorial;
177     using namespace Triangular;
178  
179     /* 直线和原的交点 */
180     int getLineCircleIntersection (Point p, Point q, Circle O, double& t1, double& t2, vector<Point>& sol) {
181         Vector v = q - p;
182         /* 使用前需清空sol */
183         //sol.clear();
184         double a = v.x, b = p.x - O.o.x, c = v.y, d = p.y - O.o.y;
185         double e = a*a+c*c, f = 2*(a*b+c*d), g = b*b+d*d-O.r*O.r;
186         double delta = f*f - 4*e*g;
187         if (dcmp(delta) < 0) return 0;
188         if (dcmp(delta) == 0) {
189             t1 = t2 = -f / (2 * e);
190             sol.push_back(p + v * t1);
191             return 1;
192         }
193  
194         t1 = (-f - sqrt(delta)) / (2 * e); sol.push_back(p + v * t1);
195         t2 = (-f + sqrt(delta)) / (2 * e); sol.push_back(p + v * t2);
196         return 2;
197     }
198  
199     /* 圆和圆的交点 */
200     int getCircleCircleIntersection (Circle o1, Circle o2, vector<Point>& sol) {
201         double d = getLength(o1.o - o2.o);
202  
203         if (dcmp(d) == 0) {
204             if (dcmp(o1.r - o2.r) == 0) return -1;
205             return 0;
206         }
207  
208         if (dcmp(o1.r + o2.r - d) < 0) return 0;
209         if (dcmp(fabs(o1.r-o2.r) - d) > 0) return 0;
210  
211         double a = getAngle(o2.o - o1.o);
212         double da = acos((o1.r*o1.r + d*d - o2.r*o2.r) / (2*o1.r*d));
213  
214         Point p1 = o1.point(a-da), p2 = o1.point(a+da);
215  
216         sol.push_back(p1);
217         if (p1 == p2) return 1;
218         sol.push_back(p2);
219         return 2;
220     }
221  
222     /* 过定点作圆的切线 */
223     int getTangents (Point p, Circle o, Vector* v) {
224         Vector u = o.o - p;
225         double d = getLength(u);
226         if (d < o.r) return 0;
227         else if (dcmp(d - o.r) == 0) {
228             v[0] = rotate(u, pi / 2);
229             return 1;
230         } else {
231             double ang = asin(o.r / d);
232             v[0] = rotate(u, -ang);
233             v[1] = rotate(u, ang);
234             return 2;
235         }
236     }
237  
238     /* a[i] 和 b[i] 分别是第i条切线在O1和O2上的切点 */
239     int getTangents (Circle o1, Circle o2, Point* a, Point* b) {
240         int cnt = 0;
241         if (o1.r < o2.r) { swap(o1, o2); swap(a, b); }
242         double d2 = getLength(o1.o - o2.o); d2 = d2 * d2;
243         double rdif = o1.r - o2.r, rsum = o1.r + o2.r;
244         if (d2 < rdif * rdif) return 0;
245         if (dcmp(d2) == 0 && dcmp(o1.r - o2.r) == 0) return -1;
246  
247         double base = getAngle(o2.o - o1.o);
248         if (dcmp(d2 - rdif * rdif) == 0) {
249             a[cnt] = o1.point(base); b[cnt] = o2.point(base); cnt++;
250             return cnt;
251         }
252  
253         double ang = acos( (o1.r - o2.r) / sqrt(d2) );
254         a[cnt] = o1.point(base+ang); b[cnt] = o2.point(base+ang); cnt++;
255         a[cnt] = o1.point(base-ang); b[cnt] = o2.point(base-ang); cnt++;
256  
257         if (dcmp(d2 - rsum * rsum) == 0) {
258             a[cnt] = o1.point(base); b[cnt] = o2.point(base); cnt++;
259         } else if (d2 > rsum * rsum) {
260             double ang = acos( (o1.r + o2.r) / sqrt(d2) );
261             a[cnt] = o1.point(base+ang); b[cnt] = o2.point(base+ang); cnt++;
262             a[cnt] = o1.point(base-ang); b[cnt] = o2.point(base-ang); cnt++;
263         }
264         return cnt;
265     }
266  
267     /* 三点确定外切圆 */
268     Circle CircumscribedCircle(Point p1, Point p2, Point p3) {  
269         double Bx = p2.x - p1.x, By = p2.y - p1.y;  
270         double Cx = p3.x - p1.x, Cy = p3.y - p1.y;  
271         double D = 2 * (Bx * Cy - By * Cx);  
272         double cx = (Cy * (Bx * Bx + By * By) - By * (Cx * Cx + Cy * Cy)) / D + p1.x;  
273         double cy = (Bx * (Cx * Cx + Cy * Cy) - Cx * (Bx * Bx + By * By)) / D + p1.y;  
274         Point p = Point(cx, cy);  
275         return Circle(p, getLength(p1 - p));  
276     }
277  
278     /* 三点确定内切圆 */
279     Circle InscribedCircle(Point p1, Point p2, Point p3) {  
280         double a = getLength(p2 - p3);  
281         double b = getLength(p3 - p1);  
282         double c = getLength(p1 - p2);  
283         Point p = (p1 * a + p2 * b + p3 * c) / (a + b + c);  
284         return Circle(p, getDistanceToLine(p, p1, p2));  
285     } 
286  
287     /* 三角形一顶点为圆心 */
288     double getPublicAreaToTriangle (Circle O, Point a, Point b) {
289         if (dcmp((a-O.o)*(b-O.o)) == 0) return 0;
290         int sig = 1;
291         double da = getPLength(O.o-a), db = getPLength(O.o-b);
292         if (dcmp(da-db) > 0) {
293             swap(da, db);
294             swap(a, b);
295             sig = -1;
296         }
297  
298         double t1, t2;
299         vector<Point> sol;
300         int n = getLineCircleIntersection(a, b, O, t1, t2, sol);
301  
302         if (dcmp(da-O.r*O.r) <= 0) {
303             if (dcmp(db-O.r*O.r) <= 0)    return getDirArea(O.o, a, b) * sig;
304  
305             int k = 0;
306             if (getPLength(sol[0]-b) > getPLength(sol[1]-b)) k = 1;
307  
308             double ret = getArea(O.o, a, sol[k]) + O.getArea(getAngle(sol[k]-O.o, b-O.o));
309             double tmp = (a-O.o)*(b-O.o);
310             return ret * sig * dcmp(tmp);
311         }
312  
313         double d = getDistanceToSegment(O.o, a, b);
314         if (dcmp(d-O.r) >= 0) {
315             double ret = O.getArea(getAngle(a-O.o, b-O.o));
316             double tmp = (a-O.o)*(b-O.o);
317             return ret * sig * dcmp(tmp);
318         }
319  
320  
321         double k1 = O.r / getLength(a - O.o), k2 = O.r / getLength(b - O.o);
322         Point p = O.o + (a - O.o) * k1, q = O.o + (b - O.o) * k2;
323         double ret1 = O.getArea(getAngle(p-O.o, q-O.o));
324         double ret2 = O.getArea(getAngle(sol[0]-O.o, sol[1]-O.o)) - getArea(O.o, sol[0], sol[1]);
325         double ret = (ret1 - ret2), tmp = (a-O.o)*(b-O.o);
326         return ret * sig * dcmp(tmp);
327     }
328  
329     double getPublicAreaToPolygon (Circle O, Point* p, int n) {
330         if (dcmp(O.r) == 0) return 0;
331         double area = 0;
332         for (int i = 0; i < n; i++) {
333             int u = (i + 1) % n;
334             area += getPublicAreaToTriangle(O, p[i], p[u]);
335         }
336         return fabs(area);
337     }
338 };
339  
340 using namespace Vectorial;
341 using namespace Circular;
342 using namespace Polygonal;
343  
344 const int maxn = 5005;
345 const double inf = 1e4;
346  
347 int N,M;
348 Point P[maxn], C;
349  
350 int main () {
351 
352         double x, y, p, q;
353         scanf("%d", &N);
354         for (int i = 0; i < N; i++) P[i].read();
355         scanf("%d",&M);
356         for(int i=1;i<=M;i++){
357         
358             scanf("%lf%lf%lf%lf", &x, &y, &p, &q);
359             double S = getArea(P, N);
360      
361             double l = 0, r = inf;
362             while (dcmp(r - l) > 0) {
363                 double mid = (l + r) / 2;
364                 double area = getPublicAreaToPolygon(Circle(Point(x, y), mid), P, N);
365                 if (dcmp(q*area-q*S+p*S) >= 0)
366                     r = mid;
367                 else
368                     l = mid;
369             }
370             double ans = (l + r) / 2;
371             printf("%.10lf\n", ans);
372         }
373     return 0;
374 }
View Code

 

posted @ 2018-07-26 20:51  Hetui  阅读(342)  评论(0编辑  收藏  举报