第14届电子科大初赛民间盗版部分题目题解

打完比赛一看,好像我就写了一道题,果然是端茶送水选手……

A - A Graph Problem

题意

给你一个图,然后有k个任务,每个任务需要从a到b点,然后让你删除最多的边,使得这k个任务仍然能够进行。

题解

卧槽,一看题,好神啊这道题,这怎么做啊,感觉不可做啊。

大胆猜一发,显然答案是小于n-1的,因为可以构成一棵树嘛。

所以我们就先瞎跑出来一棵树,然后再2^n次方去枚举这条边删不删除就好了

但是显然这样过不了嘛

那就多造几棵树,然后瞎跑,然后答案取个最小的就好了……

代码

#include <bits/stdc++.h>

using namespace std;

const int maxn = 15 + 5;
int n , m , K , dp[maxn][maxn] , mat[maxn][maxn] , ans , vis[maxn] , use[maxn] , fa[maxn] , newdp[maxn][maxn];
vector < pair < int , int > > limit;
vector < int > block;
vector < pair < int , int > > check;
vector < pair < int , int > > e;
vector < pair < int , int > > G;
vector < pair < int , int > > newe;

int find_fa(int u){
    return u != fa[u] ? fa[u] = find_fa( fa[u] ) : u;
}

void union_set(int u , int v){
	int p1 = find_fa( u ) , p2 = find_fa( v );
	if( p1 != p2 ) fa[p1] = p2;
}

void dfs(int cur){
	block.push_back(cur);
	for(int i = 1 ; i <= n ; ++ i)
		if( mat[cur][i]  && !vis[i] ){
			vis[i]=1;
			dfs( i );
		}
}

int brute_force(){
	G.clear();newe.clear();
	for(int i = 1 ; i <= n ; ++ i) fa[i] = i;
	for(auto it : e) if(use[it.first] || use[it.second]) G.push_back( it );
	int res = 0;
	for(auto it : G){
		int u = it.first , v = it.second;
		if(find_fa( u ) == find_fa( v ) ){
			res++;
			continue;
		}
		union_set( u , v );
		newe.push_back( it );
	}
	int maxdel = 0;
	for(int st = 0 ; st < (1 << newe.size()) ; ++ st){
		memset( newdp , 0 , sizeof( newdp ) );
		int del = 0;
		for(int j = 0 ; j < newe.size() ; ++ j)
			if( st >> j & 1 ){
				int u = newe[j].first;
				int v = newe[j].second;
				newdp[u][v] = newdp[v][u] = 1;
			}else del++;
		for(int k = 1 ; k <= n ; ++ k)
			for(int i = 1 ; i <= n ; ++ i)
				for(int j = 1 ; j <= n ; ++ j)
					newdp[i][j] = max( newdp[i][j] , min( newdp[i][k] , newdp[k][j] ) );
		bool ok = true;
		for(auto it : check) if(!newdp[it.first][it.second]) ok = false;
		if( ok ) maxdel = max( maxdel , del );
	}
	return res + maxdel;
}

int brute_force2(){
	G.clear();newe.clear();
	for(int i = 1 ; i <= n ; ++ i) fa[i] = i;
	for(auto it : e) if(use[it.first] || use[it.second]) G.push_back( it );
	int res = 0;
    reverse(G.begin(),G.end());
	for(auto it : G){
		int u = it.first , v = it.second;
		if(find_fa( u ) == find_fa( v ) ){
			res++;
			continue;
		}
		union_set( u , v );
		newe.push_back( it );
	}
	int maxdel = 0;
	for(int st = 0 ; st < (1 << newe.size()) ; ++ st){
		memset( newdp , 0 , sizeof( newdp ) );
		int del = 0;
		for(int j = 0 ; j < newe.size() ; ++ j)
			if( st >> j & 1 ){
				int u = newe[j].first;
				int v = newe[j].second;
				newdp[u][v] = newdp[v][u] = 1;
			}else del++;
		for(int k = 1 ; k <= n ; ++ k)
			for(int i = 1 ; i <= n ; ++ i)
				for(int j = 1 ; j <= n ; ++ j)
					newdp[i][j] = max( newdp[i][j] , min( newdp[i][k] , newdp[k][j] ) );
		bool ok = true;
		for(auto it : check) if(!newdp[it.first][it.second]) ok = false;
		if( ok ) maxdel = max( maxdel , del );
	}
	return res + maxdel;
}

int brute_force3(){
	G.clear();newe.clear();
	for(int i = 1 ; i <= n ; ++ i) fa[i] = i;
	for(auto it : e) if(use[it.first] || use[it.second]) G.push_back( it );
	for(int i = 0 , j = G.size() - 1 ; i < j ; ++ i , -- j) swap( G[i] , G[j] );
	int res = 0;
    reverse(G.begin(),G.end());
	for(auto it : G){
		int u = it.first , v = it.second;
		if(find_fa( u ) == find_fa( v ) ){
			res++;
			continue;
		}
		union_set( u , v );
		newe.push_back( it );
	}
	int maxdel = 0;
	for(int st = 0 ; st < (1 << newe.size()) ; ++ st){
		memset( newdp , 0 , sizeof( newdp ) );
		int del = 0;
		for(int j = 0 ; j < newe.size() ; ++ j)
			if( st >> j & 1 ){
				int u = newe[j].first;
				int v = newe[j].second;
				newdp[u][v] = newdp[v][u] = 1;
			}else del++;
		for(int k = 1 ; k <= n ; ++ k)
			for(int i = 1 ; i <= n ; ++ i)
				for(int j = 1 ; j <= n ; ++ j)
					newdp[i][j] = max( newdp[i][j] , min( newdp[i][k] , newdp[k][j] ) );
		bool ok = true;
		for(auto it : check) if(!newdp[it.first][it.second]) ok = false;
		if( ok ) maxdel = max( maxdel , del );
	}
	return res + maxdel;
}

int main(int argc,char *argv[]){
	scanf("%d%d%d",&n,&m,&K);
	for(int i = 1 ; i <= m ; ++ i){
		int u , v ;
		scanf("%d%d",&u,&v);
		mat[u][v] = mat[v][u] = 1;
		dp[u][v]=dp[v][u]=1;
		e.push_back(make_pair(u,v));
	}
	for(int i = 1 ; i <= K ; ++ i){
		int a , b ;
		scanf("%d%d",&a,&b);
		limit.push_back(make_pair(a,b));
	}
	for(int k = 1 ; k <= n ; ++ k)
		for(int i = 1 ; i <= n ; ++ i)
			for(int j = 1 ; j <= n ; ++ j)
				dp[i][j] = max( dp[i][j] , min( dp[i][k] , dp[k][j] ) );
	for(auto it : limit)
		if(!dp[it.first][it.second]){
			printf("-1\n");
			exit(0);
		}
	for(int i = 1 ; i <= n ; ++ i)
		if(!vis[i]){
			vis[i]=1;
			block.clear();
			dfs( i );
			check.clear();
			memset( use , 0 , sizeof( use ) );
			for( auto it : block ) use[it] = 1;
			for( auto it : limit ) if(use[it.first] || use[it.second]) check.push_back( it );
			ans += max( brute_force() , max( brute_force2() , brute_force3()) );
		}
	printf("%d\n" , ans );
	return 0;
}

B - Bank

题意

现在有面值为{0.01,0.02,0.05,0.1,0.2,0.5,1,2,5,10,20,50,100}这么多的钱,现在给你一个X,问你最少花多少钱,可以凑出面值为y的。

题解

好烦啊这道题,智障写的DFS跑的慢死了……

就只好手动去玩了,然后玩了一个小时就玩出来了,然后就完了……

代码

#include<bits/stdc++.h>
using namespace std;

bool equ(double x,double y)
{
    if(fabs(x-y)<=1e-6)return true;
    return false;
}
void solve()
{
    double x,y;
    scanf("%lf%lf",&x,&y);
    if( equ(x,2.) && equ(y,1.) ){
        printf("0.01\n");
    	return;
    }
    if( equ(x,20.) && equ(y,10.) ){
    	printf("0.01\n");
    	return;
    }
    if(equ(0.01,y))
    {
        if(equ(x,0.02))printf("0.01\n");
        else if(equ(x,0.05))printf("0.02\n");
        else printf("%.2f\n",x-0.03);
    }
    if(equ(0.02,y))
    {
        printf("0.01\n");
    }
    if(equ(0.05,y))
    {
        printf("0.01\n");
    }
    if(equ(0.1,y))
    {
        if(equ(x,0.2))printf("0.01\n");
        else printf("%.2f\n",x-0.39);
    }
    if(equ(0.2,y))
        printf("0.01\n");
    if(equ(0.5,y))
        printf("0.01\n");
    if(equ(1,y))
    {
        if(equ(x,2))printf("0.61\n");
        else printf("%.2f\n",x-3.99);
    }
    if(equ(2,y))
        printf("0.01\n");
    if(equ(5,y))
        printf("0.01\n");
    if(equ(10,y))
    {
        if(equ(x,20))printf("6.01\n");
        else printf("%.2f\n",x-39.99);
    }
    if(equ(20,y))
        printf("0.01\n");
    if(equ(50,y))
        printf("0.01\n");
}
int main()
{
    int t;scanf("%d",&t);
    while(t--)solve();
}

D - Date

题意

定义特殊的天,就是这个月的几号就是星期几。

然后给你两个日期,问你这两个日期之间,特殊的天有多少天

题解

400年一个年循环,每周七天,显然就猜一发每2800年一个循环嘛

然后我们就暴力模拟2800年,然后剩下的就取余数什么的乱搞搞就完了……

代码

#include <bits/stdc++.h>

using namespace std;

int T,Y1,Y2,M1,M2,D1,D2,cnt;
int ans[2810][13];
long long ret;

int solve(int year,int month,int day)
{
    if(month<3)
    {
        year-=1;
        month+=12;
    }
    int c=year/100,y=year-100*c;
    int w=c/4-2*c+y+y/4+(26*(month+1)/10)+day-1;
    w=(w%7+7)%7;
    if(w==day) return 1;else return 0;
}

int main()
{
    scanf("%d",&T);
    for(int i=0;i<2800;i++)
    {
        for(int j=1;j<=12;j++)
        {
            ans[i][j]=solve(i,j,1);
            if(ans[i][j]) cnt++;
        }
    }
    cnt*=7;
    while(T--)
    {
        scanf("%d%d%d%d%d%d",&Y1,&M1,&D1,&Y2,&M2,&D2);
        ret=0LL;
        if(Y1==Y2)
        {
            if(M1==M2)
            {
                if(D1<=7)ret+=1LL*ans[Y1%2800][M1]*(min(7,D2)+1-D1);
            }
            else
            {
                if(D1<=7)ret+=1LL*ans[Y1%2800][M1]*(8-D1);
                ret+=1LL*ans[Y1%2800][M2]*min(7,D2);
                for(int j=M1+1;j<=M2-1;j++)
                {
                    ret+=1LL*ans[Y1%2800][j]*7;
                }
            }
            cout<<ret<<endl;
            continue;
        }
        int p1=Y1+1,p2=Y2-1;
        if(D1<=7)ret+=1LL*ans[Y1%2800][M1]*(8-D1);
        for(int j=M1+1;j<=12;j++)
        {
            ret+=1LL*ans[Y1%2800][j]*7;
        }
        for(int i=Y1+1;i<Y2;i++,p1++)
        {
            if(i%2800==0) break;
            for(int j=1;j<=12;j++)
            {
                ret+=1LL*ans[i%2800][j]*7;
            }
        }
        ret+=1LL*ans[Y2%2800][M2]*min(7,D2);
        for(int j=1;j<=M2-1;j++)
        {
            ret+=1LL*ans[Y2%2800][j]*7;
        }
        for(int i=Y2-1;i>Y1;i--,p2--)
        {
            if(i<p1||i%2800==2799) break;
            for(int j=1;j<=12;j++)
            {
                ret+=1LL*ans[i%2800][j]*7;
            }
        }
        ret+=1LL*cnt*(max(0,(p2-p1+1))/2800);
        cout<<ret<<endl;
    }
}

E - Easy Problem

题意

给你n个串,然后你需要构造一个串,使得这个串的权值最大

权值计算为sigma(ci*tot(s,i)),tot(s,i)表示你构造的串在第i个串里面出现的次数

题解

显然构造的串长度为1最好,这样出现的次数肯定是最大的

然后枚举26个字母搞一波就完了……

代码

#include <bits/stdc++.h>

using namespace std;
const int maxn = 1e5 + 500;

int n , c[maxn] , num[maxn][26];
char temp[maxn];

int main(int argc,char *argv[]){
    scanf("%d",&n);
	for(int i = 1 ; i <= n ; ++ i){
		scanf("%s",temp);
		int len = strlen(temp);
		for(int j = 0 ; j < len ; ++ j) num[i][temp[j]-'a']++;
	}
	for(int i = 1 ; i <= n ; ++ i) scanf("%d" , c + i);
	long long ans = 0;
	for(int i = 0 ; i < 26 ; ++ i){
		long long tmp = 0;
		for(int j = 1 ; j <= n ; ++ j) tmp += 1LL*num[j][i]*c[j];
		ans=max(ans,tmp);
	}
	printf("%lld\n",ans);
	return 0;
}

F - Find the Stuff

题意

每个房间有xi个人,有一个机器人一开始在一号房间,然后抓取这个房间序号最小的人

然后又走到第二个房间,抓取第二个房间最小的人,然后一直循环。

Q次询问,问你他抓的第k个人是谁。

题解

只有询问嘛,离线搞一波

线段树强行去怼就好了,机器人可能会转很多圈嘛,这个一次性擦去就好了……

然后就相当于权值线段树上查询第k大了,二分瞎逼去找就好了

代码

#include <bits/stdc++.h>

using namespace std;
const int maxn = 1e5 + 500;
int x[maxn],y[maxn],n,m;
pair < long long , int > Query[maxn];
pair < int , int > ans[maxn];

struct Segmenttree
{
    struct treenode
	{
	   int L , R  ;
	   int minv , num ;
	};

	treenode tree[maxn * 4];

	inline void push_up(int o){
		int lson = o << 1 , rson = o << 1 | 1;
		tree[o].minv = min(tree[lson].minv , tree[rson].minv);
		tree[o].num = tree[lson].num + tree[rson].num;
	}

	void build(int L , int R , int o){
		tree[o].L = L , tree[o].R = R;
		if (R > L){
			int mid = (L+R) >> 1;
			build(L,mid,o<<1);
			build(mid+1,R,o<<1|1);
			push_up( o );
		}else tree[o].minv = x[L] , tree[o].num = 1;
	}

	void updata(int QL,int QR,int o){
		int L = tree[o].L , R = tree[o].R;
		if (QL <= L && R <= QR) tree[o].minv=2e9,tree[o].num=0;
		else{
			int mid = (L+R)>>1;
			if (QL <= mid) updata(QL,QR,o<<1);
			if (QR >  mid) updata(QL,QR,o<<1|1);
			push_up(o); 
		}
	}
	
	int Search(int QL,int QR,int o){
		int L = tree[o].L , R = tree[o].R;
		if (L == R) return L;
		else{
			int mid = (L+R)>>1;
			int lson = o << 1 , rson = o << 1 | 1;
			if( tree[lson].minv < tree[rson].minv ) return Search( QL , QR , lson );
			return Search( QL , QR , rson );
		}
	}

	int Binary_Search(int o , int kth){
		int L = tree[o].L , R = tree[o].R;
		if (L == R) return L;
		else{
			int mid = (L+R)>>1;
			int lson = o << 1 , rson = o << 1 | 1;
			if( tree[lson].num >= kth ) return Binary_Search( lson , kth );
			return Binary_Search( rson , kth - tree[lson].num);
		}
	}

}Sgtree;


int main(int argc,char *argv[]){
	scanf("%d%d",&n,&m);
	for(int i = 1 ; i <= n ; ++ i) scanf("%d" , x + i );
	for(int i = 1 ; i <= m ; ++ i){
		scanf("%lld",&Query[i].first);
		Query[i].second = i;
	}
	sort( Query + 1 , Query + 1 + m );
	Sgtree.build( 1 , n , 1 );
	long long cur = 0;
	int alive = n ;
	int extra = 0;
	int pre = 0;
	for(int i = 1 ; i <= m ; ++ i){
		while( cur + 1LL * (Sgtree.tree[1].minv - pre) * alive  < Query[i].first ){
			cur += 1LL * (Sgtree.tree[1].minv-pre) * alive;
			extra = Sgtree.tree[1].minv;
			alive--;
			int pos = Sgtree.Search( 1 , n , 1 );
			pre = x[pos];
			Sgtree.updata( pos , pos , 1 );
		}
		int rk = ( Query[i].first - cur ) % alive ;
		if( rk == 0 ) rk = alive;
		int Pos = Sgtree.Binary_Search( 1 , rk );
		//cout << Query[i].first << " " << cur << endl;
		int index = (alive - 1 + Query[i].first - cur) / alive + extra;
		int ansidx = Query[i].second;
		ans[ansidx].first = Pos , ans[ansidx].second = index;
		//if( i == 1 ) break;
	}
	for(int i = 1 ; i <= m ; ++ i) printf("%d %d\n",ans[i].first,ans[i].second);
	return 0;
}

G - Good Water Problem

题意

给你n个数,你每次可以选择2个数x,y出来,然后把这两个数变成lcm(x,y)和gcd(x,y)

你可以变化无数次。

你的目标使得最后的最大数尽量大,然后保证第二大的数尽量大。。。。。保证最小的数尽量大

让你输出最后的n个数是啥

题解

猜一波结论,gcd和lcm实质上就是质因数的交换,gcd取质因数的min,lcm取质因数的max

然后最大的数,显然就是所有质因数中的max,第二大的就是所有质因数的第二大。。。。

然后一直下去就好了

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+7;
const int mod = 1e9+7;
vector<int>E[maxn];
int n;
int p[maxn];
int pri[maxn];
long long ans[maxn];
int cnt=0;
long long quickpow(long long  m,long long n,long long k)//返回m^n%k
{
    long long b = 1;
    while (n > 0)
    {
          if (n & 1)
             b = (b*m)%k;
          n = n >> 1 ;
          m = (m*m)%k;
    }
    return b;
}
void get_pri()
{
    for(int i=2;i<maxn;i++)
    {
        if(p[i])continue;
        pri[cnt++]=i;
        for(int j=i+i;j<maxn;j+=i)
            p[j]=1;
    }
    return;
}
bool cmp(int a,int b)
{
    return a>b;
}
void init()
{
    for(int i=0;i<cnt;i++)
        E[i].clear();
    for(int i=0;i<maxn;i++)
        ans[i]=1;
}
void get(int x)
{
    for(int i=0;i<cnt;i++)
    {
        if(pri[i]>sqrt(maxn)) break;
        if(x%pri[i]==0)
        {
            int tot = 0;
            while(x%pri[i]==0)
            {
                x/=pri[i];
                tot++;
            }
            E[i].push_back(tot);
        }
    }
    if(x>1)
    {
        int pos=lower_bound(pri,pri+cnt,x)-pri;
        E[pos].push_back(1);
    }
}
void solve()
{
    init();
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        get(x);
    }

    for(int i=0;i<cnt;i++)
        sort(E[i].begin(),E[i].end(),cmp);

    for(int i=0;i<cnt;i++)
        for(int j=0;j<E[i].size();j++)
            ans[j]=(ans[j]*quickpow(pri[i],E[i][j],mod))%mod;

    for(int i=0;i<n-1;i++)
        printf("%lld ",ans[i]);
    printf("%lld\n",ans[n-1]);
}
int main()
{
    get_pri();
    int t;scanf("%d",&t);
    while(t--)solve();
}

H - Happy Shape

题意

给你一个圆,给你一个矩形,问你这俩东西相交的面积是多少

题解

卧槽,裸的三角剖分呀,套版套版!

然后挂精度挂精度,从1e-8调整到1e-10,然后全部改成long double,精度变成1e-7就怼过去了……

代码

#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<vector>
const double eps=1e-7;
const double PI=acos(-1.0);

using namespace std;


struct Point{
    long double x;
    long double y;
    Point(long double x=0,long double y=0):x(x),y(y){}
    void operator<<(Point &A) {cout<<A.x<<' '<<A.y<<endl;}
};

int dcmp(long double x)  {return (x>eps)-(x<-eps); }
int sgn(long double x)  {return (x>eps)-(x<-eps); }
typedef  Point  Vector;

Vector  operator +(Vector A,Vector B) { return Vector(A.x+B.x,A.y+B.y);}

Vector  operator -(Vector A,Vector B) { return Vector(A.x-B.x,A.y-B.y); }

Vector  operator *(Vector A,long double p) { return Vector(A.x*p,A.y*p);  }

Vector  operator /(Vector A,long double p) {return Vector(A.x/p,A.y/p);}



ostream &operator<<(ostream & out,Point & P) { out<<P.x<<' '<<P.y<<endl; return out;}
//
bool  operator< (const Point &A,const Point &B) { return dcmp(A.x-B.x)<0||(dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)<0); }

bool  operator== ( const Point &A,const Point &B) { return dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)==0;}


long double  Dot(Vector A,Vector B) {return A.x*B.x+A.y*B.y;}

long double  Cross(Vector A,Vector B)  {return A.x*B.y-B.x*A.y; }

long double  Length(Vector A)  { return sqrt(Dot(A, A));}


long double  Angle(Vector A,Vector B) {return acos(Dot(A,B)/Length(A)/Length(B));}

long double  Area2(Point A,Point B,Point C ) {return Cross(B-A, C-A);}

Vector Rotate(Vector A,long double rad) { return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));}
Vector Normal(Vector A) {long double L=Length(A);return Vector(-A.y/L,A.x/L);}

Point GetLineIntersection(Point P,Vector v,Point Q,Vector w)
{
    Vector u=P-Q;
    long double t=Cross(w, u)/Cross(v,w);
    return P+v*t;

}

long double DistanceToLine(Point P,Point A,Point B)
{
    Vector v1=P-A; Vector v2=B-A;
    return fabs(Cross(v1,v2))/Length(v2);

}

long double DistanceToSegment(Point P,Point A,Point B)
{
    if(A==B)  return Length(P-A);

    Vector v1=B-A;
    Vector v2=P-A;
    Vector v3=P-B;

    if(dcmp(Dot(v1,v2))==-1)    return  Length(v2);
    else if(Dot(v1,v3)>0)    return Length(v3);

    else return DistanceToLine(P, A, B);

}

Point GetLineProjection(Point P,Point A,Point B)
{
    Vector v=B-A;
    Vector v1=P-A;
    long double t=Dot(v,v1)/Dot(v,v);

    return  A+v*t;
}

bool  SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2)
{
    long double c1=Cross(b1-a1, a2-a1);
    long double c2=Cross(b2-a1, a2-a1);
    long double c3=Cross(a1-b1, b2-b1);
    long double c4=Cross(a2-b1, b2-b1);

    return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0 ;

}

bool  OnSegment(Point P,Point A,Point B)
{
    return dcmp(Cross(P-A, P-B))==0&&dcmp(Dot(P-A,P-B))<=0;
}

long double PolygonArea(Point *p,int n)
{
    long double area=0;

    for(int i=1;i<n-1;i++)
    {
        area+=Cross(p[i]-p[0], p[i+1]-p[0]);

    }
    return area/2;

}

Point  read_point()
{
    Point P;
    scanf("%Lf%Lf",&P.x,&P.y);
    return  P;
}

// ---------------与圆有关的--------

struct Circle
{
    Point c;
    long double r;

    Circle(Point c=Point(0,0),long double r=0):c(c),r(r) {}

    Point point(long double a)
    {
        return Point(c.x+r*cos(a),c.y+r*sin(a));
    }


};

struct  Line
{
    Point p;
    Vector v;
    Line(Point p=Point(0,0),Vector v=Vector(0,1)):p(p),v(v) {}

    Point point(long double t)
    {
        return Point(p+v*t);
    }

};

int getLineCircleIntersection(Line L,Circle C,long double &t1,long double &t2,vector<Point> &sol)
{
    long double a=L.v.x;
    long double b=L.p.x-C.c.x;
    long double c=L.v.y;
    long double d=L.p.y-C.c.y;

    long double e=a*a+c*c;
    long double f=2*(a*b+c*d);
    long double g=b*b+d*d-C.r*C.r;

    long double delta=f*f-4*e*g;

    if(dcmp(delta)<0) return 0;

    if(dcmp(delta)==0)
    {
        t1=t2=-f/(2*e);
        sol.push_back(L.point(t1));
        return 1;
    }

    else
    {
        t1=(-f-sqrt(delta))/(2*e);
        t2=(-f+sqrt(delta))/(2*e);

        sol.push_back(L.point(t1));
        sol.push_back(L.point(t2));

        return 2;
    }

}

// 向量极角公式

long double angle(Vector v)  {return atan2(v.y,v.x);}

int getCircleCircleIntersection(Circle C1,Circle C2,vector<Point> &sol)
{
    long double d=Length(C1.c-C2.c);

    if(dcmp(d)==0)
    {
        if(dcmp(C1.r-C2.r)==0)  return -1;  // 重合
        else return 0;    //  内含  0 个公共点
    }

    if(dcmp(C1.r+C2.r-d)<0)  return 0;  // 外离
    if(dcmp(fabs(C1.r-C2.r)-d)>0)  return 0;  // 内含

    long double a=angle(C2.c-C1.c);
    long double da=acos((C1.r*C1.r+d*d-C2.r*C2.r)/(2*C1.r*d));

    Point p1=C1.point(a-da);
    Point p2=C1.point(a+da);

    sol.push_back(p1);

    if(p1==p2)  return 1; // 相切
    else
    {
        sol.push_back(p2);
        return 2;
    }
}


//  求点到圆的切线

int getTangents(Point p,Circle C,Vector *v)
{
    Vector u=C.c-p;

    long double dist=Length(u);

    if(dcmp(dist-C.r)<0)  return 0;

    else if(dcmp(dist-C.r)==0)
    {
        v[0]=Rotate(u,PI/2);
        return 1;
    }

    else
    {

        long double ang=asin(C.r/dist);
        v[0]=Rotate(u,-ang);
        v[1]=Rotate(u,+ang);
        return 2;
    }

}

//  求两圆公切线


int getTangents(Circle A,Circle B,Point *a,Point *b)
{
    int cnt=0;

    if(A.r<B.r)
    {
        swap(A,B); swap(a, b);  //  有时需标记
    }

    long double d=Length(A.c-B.c);

    long double rdiff=A.r-B.r;
    long double rsum=A.r+B.r;

    if(dcmp(d-rdiff)<0)  return 0;   // 内含

    long double base=angle(B.c-A.c);

    if(dcmp(d)==0&&dcmp(rdiff)==0)   return -1 ;  // 重合 无穷多条切线

    if(dcmp(d-rdiff)==0)             // 内切   外公切线
    {
        a[cnt]=A.point(base);
        b[cnt]=B.point(base);
        cnt++;
        return 1;
    }

    // 有外公切线的情形

    long double ang=acos(rdiff/d);
    a[cnt]=A.point(base+ang);
    b[cnt]=B.point(base+ang);
    cnt++;
    a[cnt]=A.point(base-ang);
    b[cnt]=B.point(base-ang);
    cnt++;

    if(dcmp(d-rsum)==0)     // 外切 有内公切线
    {
        a[cnt]=A.point(base);
        b[cnt]=B.point(base+PI);
        cnt++;
    }

    else  if(dcmp(d-rsum)>0)   // 外离   又有两条外公切线
    {
        long double  ang_in=acos(rsum/d);
        a[cnt]=A.point(base+ang_in);
        b[cnt]=B.point(base+ang_in+PI);
        cnt++;
        a[cnt]=A.point(base-ang_in);
        b[cnt]=B.point(base-ang_in+PI);
        cnt++;
    }

    return cnt;
}



Point Zero=Point(0,0);

long double  common_area(Circle C,Point A,Point B)
{
   // if(A==B)  return 0;
    if(A==C.c||B==C.c)  return 0;

    long double  OA=Length(A-C.c),OB=Length(B-C.c);
    long double  d=DistanceToLine(Zero, A, B);

    int sg=sgn(Cross(A,B));
    if(sg==0)  return 0;

    long double angle=Angle(A,B);

    if(dcmp(OA-C.r)<=0&&dcmp(OB-C.r)<=0)
    {
        return Cross(A,B)/2;

    }

    else if(dcmp(OA-C.r)>=0&&dcmp(OB-C.r)>=0&&dcmp(d-C.r)>=0)
    {
        return  sg*C.r*C.r*angle/2;

    }
    else if (dcmp(OA-C.r)>=0&&dcmp(OB-C.r)>=0&&dcmp(d-C.r)<0)
    {


        Point prj=GetLineProjection(Zero, A, B);

        if(OnSegment(prj, A, B))
        {
        vector<Point> p;
        Line L=Line(A,B-A);
        long double t1,t2;
        getLineCircleIntersection(L,C, t1, t2, p);

        long double s1=0;
        s1=C.r*C.r*angle/2;

        long double s2=0;
        s2=C.r*C.r*Angle(p[0],p[1])/2;
        s2-=fabs(Cross(p[0],p[1])/2);
        s1=s1-s2;

        return  sg*s1;
        }

        else
        {
            return sg*C.r*C.r*angle/2;
        }

    }
    else
    {

            if(dcmp(OB-C.r)<0)
            {

                Point temp=A;
                A=B;
                B=temp;
            }

         Point inter_point;

            long double t1,t2;
            Line L=Line(A,B-A);
            vector<Point> inter;
            getLineCircleIntersection(L, C, t1, t2,inter);

                    if(OnSegment(inter[0], A, B))
                inter_point=inter[0];
            else
            {
                inter_point=inter[1];

            }


//        两种方法求交点都可以
//        Point  prj=GetLineProjection(Zero, A, B);
//
//        Vector v=B-A;
//        v=v/Length(v);
//        long double mov=sqrt(C.r*C.r-d*d);
//
//        if(OnSegment(prj+v*mov, A, B))
//        {
//            inter_point=prj+v*mov;
//        }
//        else
//        {
//            inter_point=prj+Vector(-v.x,-v.y)*mov;
//        }


            long double s=fabs(Cross(inter_point, A)/2);
            s+=C.r*C.r*Angle(inter_point,B)/2;

            return s*sg;


    }
}

void solve(int cas)
{
    double area;
    double xr,yr,rr;
    scanf("%lf%lf%lf",&xr,&yr,&rr);
    Point a[60];
    double R;int n;
    Circle C(Zero,0);
    R = rr;C.r=R;
    n = 4;
    double xx1,yy1,xx2,yy2,ans=0;
    scanf("%lf%lf",&xx1,&yy1);
    scanf("%lf%lf",&xx2,&yy2);
    a[0].x=xx1-xr,a[0].y=yy1-yr;
    a[1].x=xx1-xr,a[1].y=yy2-yr;
    a[2].x=xx2-xr,a[2].y=yy2-yr;
    a[3].x=xx2-xr,a[3].y=yy1-yr;
    a[n]=a[0];
    for(int i=0;i<n;i++)
        ans+=common_area(C, a[i], a[i+1]);
    printf("Case #%d: %.4f\n",cas,fabs(ans));
}

int main()
{
    int t;scanf("%d",&t);
    for(int i=1;i<=t;i++)
        solve(i);
    return 0;
}

I - Infinity Set

题意

一开始集合里面只有x,y,然后这个集合有一个性质,如果x在里面,y在里面的话,那么(x+y)也在里面

然后Q次询问,问你第k大的是啥

题解

里面的东西,很像exgcd的那个玩意儿嘛,都是ax+by的这种

然后我们暴力前lcm(a,b)的所有数,然后剩下的我们就大胆猜一发就好了,每次增加的都是gcd

至于为什么,这个得问霄老爷,我反正是数学智障……

对了排序,得用基数排序……

代码

#include <bits/stdc++.h>

using namespace std;

int v[5005*5005];

int gcd(int x,int y)
{
    if(x%y==0) return y;else return gcd(y,x%y);
}

int main()
{
    int n;
    int k,a,b;
    scanf("%d%d",&a,&b);
    scanf("%d",&n);
    int g=gcd(a,b);
    int l=a*b/g;
    if(a>b) swap(a,b);
    int tot=0,cnt=0;
    for(int i=0;i<l;i+=a)
    {
        for(int j=0;j<l;j+=b)
        {
            if(i+j>=l) break;
            v[i+j]=1;
        }
    }
    for(int i=0;i<5005*5005;i++)
        if(v[i])v[tot++]=i;
    for(int i=0;i<n;i++)
    {
        scanf("%d",&k);
        if(k<tot) printf("%d\n",v[k]);
            else printf("%lld\n",1LL*(k-tot)*g+l);
    }
    return 0;
}

J - Just a Magic String

题意

定义一个无穷长的字符串s,这个字符串一开始只有a

然后把这个串的a变成b,b变成a扔在后面

然后一直循环下去

现在给你一个串s,问你这个串出现在字符串s的最早时间是多少

或者压根就没出现过。

题解

只需要暴力就好了,只要暴力出6*2^20长度就好了

证明如下:设02^20-1组成的字符串为A,2^202^20*2-1组成的字符串为B

那么魔法串为ABBABAAB....

因为输入的串只有10^6小于A和B的长度

只有两种可能

一种是输入的串在A和B的一个里面

一种是穿过AA, AB, BA, BB中间

所以只需要判断ABBABAAB就可以了

然后就完了。

代码:

#include <bits/stdc++.h>
#define input_fast std::ios::sync_with_stdio(false);std::cin.tie(0)
using namespace std;
const int maxn = 1e6 + 50;
int fail[maxn];
string S = "a";
string T;

void init(){
    while( S.size() < 3e6 ){
		string temp = S;
		for(int i = 0 ; i < temp.size() ; ++ i){
			if(temp[i]=='a')
				S.push_back('b');
			else
				S.push_back('a');
		}
	}
}

int main(int argc,char *argv[]){
	input_fast;
	init();
	cin >> T;
	fail[0]=fail[1]=0;
	for(int i = 1 ; i < T.size() ; ++ i){
		int j = fail[i];
		while( j && T[j] != T[i] ) j = fail[j];
		fail[i+1] = T[j]==T[i]?j+1:0;
	}
	int j = 0;
	int ans = -1;
	for(int i = 0 ; i < S.size() ; ++ i){
		while( j && S[i] != T[j] ) j = fail[j];
		if(S[i]==T[j]) j ++;
		if( j == T.size() ){
			ans = i - T.size() + 2;
			break;
		}
	}
	cout << ans << endl;
	return 0;
}
posted @ 2016-03-27 11:06  qscqesze  阅读(383)  评论(0编辑  收藏  举报