• 第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
    ");
    			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
    " , 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
    ");
        	return;
        }
        if( equ(x,20.) && equ(y,10.) ){
        	printf("0.01
    ");
        	return;
        }
        if(equ(0.01,y))
        {
            if(equ(x,0.02))printf("0.01
    ");
            else if(equ(x,0.05))printf("0.02
    ");
            else printf("%.2f
    ",x-0.03);
        }
        if(equ(0.02,y))
        {
            printf("0.01
    ");
        }
        if(equ(0.05,y))
        {
            printf("0.01
    ");
        }
        if(equ(0.1,y))
        {
            if(equ(x,0.2))printf("0.01
    ");
            else printf("%.2f
    ",x-0.39);
        }
        if(equ(0.2,y))
            printf("0.01
    ");
        if(equ(0.5,y))
            printf("0.01
    ");
        if(equ(1,y))
        {
            if(equ(x,2))printf("0.61
    ");
            else printf("%.2f
    ",x-3.99);
        }
        if(equ(2,y))
            printf("0.01
    ");
        if(equ(5,y))
            printf("0.01
    ");
        if(equ(10,y))
        {
            if(equ(x,20))printf("6.01
    ");
            else printf("%.2f
    ",x-39.99);
        }
        if(equ(20,y))
            printf("0.01
    ");
        if(equ(50,y))
            printf("0.01
    ");
    }
    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
    ",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
    ",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
    ",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
    ",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
    ",v[k]);
                else printf("%lld
    ",1LL*(k-tot)*g+l);
        }
        return 0;
    }
    

    J - Just a Magic String

    题意

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

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

    然后一直循环下去

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

    或者压根就没出现过。

    题解

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

    证明如下:设0~2^20-1组成的字符串为A,2^20~2^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;
    }
  • 相关阅读:
    iOS7以上自定义一个navigationController,并沿用系统的侧滑返回效果
    判断一个日期是否再某个日期范围内object-c 范例
    统计软件简介
    大学生对vivo手机的看法
    第二次作业,制作调查问卷
    作业一:数据软件系统的介绍及spss的操作简介
    Android WebView
    Android ListView
    ARM和x86
    android shape和selector
  • 原文地址:https://www.cnblogs.com/qscqesze/p/5325166.html
Copyright © 2020-2023  润新知