第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;
}