ICL 2016


ICL 2016

A ( √ ) (√) ()
B
C ( √ ) (√) ()
D ( √ ) (√) ()
E
F ( √ ) (√) ()
G ( √ ) (√) ()
H ( √ ) (√) ()
I ( √ ) (√) ()
J
K
L
M ( √ ) (√) ()

A Three seamarks

题意:给出点M1,M2,M3的坐标,和角M1KM2,M2KM3的大小,求点K的坐标。
题解:两个圆相交,一个交点为M2,另一个为答案。注意四点共圆的情况。

#include<iostream>
#include<cmath>
#include<iomanip>
using namespace std;
const double eps=1e-6;
const double pi=acos(-1.0);
const double eps2 = 1e-2;
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; }
    bool operator==(point b)const {
        return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
    }
    point operator+(const point& b)const {
        return point(x + b.x, y + b.y);
    }
    point operator-(const point& b)const {
        return point(x - b.x, y - b.y);
    }
}m[3];
struct circle {
	double x,y,r;
	circle(){}
	circle(double _x,double _y,double _r){x=_x,y=_y,r=_r;}
}c[4];
double angle1,angle2;
int flag;
int cnt=0;
point fun(point a,point b,point c){//三点共圆圆心公式
    double x=((a.x*a.x-b.x*b.x+a.y*a.y-b.y*b.y)*(a.y-c.y)-(a.x*a.x-c.x*c.x+a.y*a.y-c.y*c.y)*(a.y-b.y) ) / (2*(a.y-c.y)*(a.x-b.x)-2*(a.y-b.y)*(a.x-c.x));
    double y=((a.x*a.x-b.x*b.x+a.y*a.y-b.y*b.y)*(a.x-c.x)-(a.x*a.x-c.x*c.x+a.y*a.y-c.y*c.y)*(a.x-b.x) ) / (2*(a.y-b.y)*(a.x-c.x)-2*(a.y-c.y)*(a.x-b.x));
    return point(x,y);
}
double getdis2(point a,point b){
	return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
void getcircle(point a,point b,double ang){//已知两点和圆周角求出两个可能的圆 
    ang = (ang < pi * 0.5 ? ang: pi - ang);
    point mid;
    mid.x = (a.x + b.x) * 0.5;
    mid.y = (a.y + b.y) * 0.5;
    if(ang + eps < pi * 0.5){
        double tan1 = tan(ang);
        c[cnt].x = mid.x + (a.y - mid.y) / tan1;
        c[cnt].y = mid.y - (a.x - mid.x) / tan1;
        c[cnt].r = sqrt(getdis2(mid , point(c[cnt].x, c[cnt].y)) +getdis2(mid , a));
        ++cnt;
        c[cnt].x = mid.x - (a.y - mid.y) / tan1;
        c[cnt].y = mid.y + (a.x - mid.x) / tan1;
        c[cnt].r = c[cnt - 1].r;
        ++cnt;
    }
    else{
        c[cnt].x = mid.x;
        c[cnt].y = mid.y;
        c[cnt].r = sqrt(getdis2(mid , a));
        ++cnt;
        c[cnt] = c[cnt - 1];
        ++cnt;
    }
}
double mycos(double B, double C, double A){
    return (B * B + C * C - A * A) / (B * C * 2);
}
double mycos2(point a,point b, point c)
{
    double C2 = getdis2(a,b), A2 = getdis2(b,c), B2 = getdis2(c,a);
    return (B2 + C2 - A2) / (sqrt(B2 * C2) * 2);
}
bool checkpoint(point re){
    for(int i = 0; i < 3; ++i)
        if(getdis2(m[i],re) < eps)
            return 0;
    double tmp = acos(mycos2(re, m[0], m[1])) - angle1 - pi;
    while(tmp < -eps2)
        tmp += pi;
    if(abs(tmp) > eps2)
        return 0;
    tmp = acos(mycos2(re, m[1], m[2])) - angle2 - pi;
    while(tmp < -eps2)
        tmp += pi;
    return abs(tmp) < eps2;
}
void getpoint2(circle c1){
    double dab = sqrt(getdis2(m[0],m[1]));
    double ang = acos(dab / (c1.r * 2));
    ang -= angle1;
    double len = c1.r * 2 * cos(ang);
    double cang1 = cos(angle1);
    double l2 = len * cang1;
    point d, re;
    d.x = m[1].x + (m[0].x - m[1].x) * l2 / dab;
    d.y = m[1].y + (m[0].y - m[1].y) * l2 / dab;
    double l3 = len * sqrt(1 - cang1 * cang1);
    re.x = d.x + (m[0].y - m[1].y) * l3 / dab;
    re.y = d.y - (m[0].x - m[1].x) * l3 / dab;
    if(checkpoint(re))
    {
        printf("%.8f %.8f\n", re.x, re.y);
        flag = 1;
        return;
    }
    re.x = d.x - (m[0].y - m[1].y) * l3 / dab;
    re.y = d.y + (m[0].x - m[1].x) * l3 / dab;
    if(checkpoint(re))
    {
        printf("%.8f %.8f\n", re.x, re.y);
        flag = 1;
        return;
    }
}
point rotate(point p, double cost, double sint){
    double x = p.x, y = p.y;
    return point(x * cost - y * sint, x * sint + y * cost);
}
void getpoint(circle c1, circle c2){//求两圆交点 
    double dab = sqrt(getdis2(point(c1.x,c1.y) , point(c2.x, c2.y)));
    if(dab < eps){
        getpoint2(c1);
        return;
    }
    if(c1.r > c2.r)
        swap(c1, c2);
    double cost = mycos(c1.r, dab, c2.r);
    double sint = sqrt(1 - cost * cost);
    point re = rotate(point(c2.x, c2.y) - point(c1.x, c1.y), cost, sint);
    re.x = c1.x + re.x * (c1.r / dab);
    re.y = c1.y + re.y * (c1.r / dab);
    if(getdis2(m[1] , re) < eps){
        re = rotate(point(c2.x, c2.y) - point(c1.x, c1.y), cost, -sint);
        re.x = c1.x + re.x * (c1.r / dab);
        re.y = c1.y + re.y * (c1.r / dab);
    }
    if(!checkpoint(re))
        return;
    flag = 1;
    printf("%.8f %.8f\n", re.x, re.y);
}
void solve(){
	for(int i=0;i<3;++i)
		cin>>m[i].x>>m[i].y;
	cin>>angle1>>angle2;
	angle1=angle1*pi/180;
	angle2=angle2*pi/180;
	cnt=0;
	getcircle(m[0],m[1],angle1);
	getcircle(m[1],m[2],angle2);
	flag=0;
    getpoint(c[0], c[2]);
    if(!flag)
        getpoint(c[0], c[3]);
    if(!flag)
        getpoint(c[1], c[2]);
    if(!flag)
        getpoint(c[1], c[3]);
}
int main(){
	int t=1;
	cin>>t;
	while(t--){
		solve();
	}
} 

C Cubes

题意:
n n n个骰子, n n n个骰子垂直放置。
第一行给出你目前看见的从上到下骰子的面的字符串。
第二行给出你想要通过转动骰子形成的字符串。(只能水平转动)
问形成的概率。
可以分解成每一个骰子的概率相乘。如果目标状态在目前状态的对立面,那么必定在一个水平方向上,概率为1。如果不在对立面上,那么可能在水平面也可能在垂直面里,概率为0.5。(这是目标状态字母和目前状态字母只存在一个的情况。)
如果存在多个目标状态的字母和目前状态的字母。只需要处理下目标状态字母所在的面,对每一个目前状态字母计算概率,取平均值就行了。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
using namespace std;
#define ll long long
#define maxn 100100 
#define mod 1000000009
#define eps 1e-10
#define inf 0x3f3f3f3f
template <typename T>
inline void read(T& X) {
	X = 0; int w = 0; char ch = 0;
	while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
	while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
	if (w) X = -X;
}
int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	string a,b;
	string s;
	cin>>a>>b;
	int len=a.length();
	double ans=1;//总概率
	for(int i=0;i<len;i++){
		cin>>s;
		double p=0;//一个目前状态的概率
		double ansp=0;//当前一个骰子的概率
		int k=0;//目前状态出现的次数
		int vis[5]={0};
		for(int j=0;j<6;j++){
			if(s[j]==b[i]){
				if(j==0||j==5)vis[1]++;//前后面有目标状态
				else if(j==1||j==3)vis[2]++;//上下面有目标状态
				else if(j==2||j==4)vis[3]++;//左右面有目标状态
			}
		}
		for(int j=0;j<6;j++){
			p=0;
			if(s[j]==a[i]){
				k++;
				if(j==0||j==5){
					if(vis[2])p+=0.5;//非对立面存在目标状态,概率+0.5
					if(vis[3])p+=0.5;
					if(vis[1])p=1.0;//如果对立面存在目标状态,概率为1
				}
				else if(j==1||j==3){
					if(vis[1])p+=0.5;
					if(vis[3])p+=0.5;
					if(vis[2])p=1.0;
				}
				else if(j==2||j==4){
					if(vis[1])p+=0.5;
					if(vis[2])p+=0.5;
					if(vis[3])p=1.0;
				}
			}
			ansp+=p;
		}
		ansp=ansp/1.0/k;//除以k次目前状态,取平均值
		ans=ans*ansp;
	}
	cout<<ans<<endl;
    return 0;
}

D Camelogistics

题意:骆驼要把N个苹果从起点运到L千米外的终点,骆驼最大载重为K个苹果,路上每隔一公里都有一个存放站,骆驼每走一公里需要吃掉一个苹果,问最多可以把多少个苹果送到终点?

题解:骆驼每走一步,易得吃掉的苹果是搬运次数的两倍减一。每一趟骆驼都搬运K个苹果,这样搬运是最优的。对于最后剩下的苹果来说,因为去前一个点搬运苹果一趟消耗的苹果为2,所以,当剩下的苹果不足2时,我们可以直接舍弃那些苹果。
所以我们只需要维护搬运次数,搬运次数相同的情况下,每走一千米消耗的苹果数一样。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
using namespace std;
#define ll long long
#define maxn 100100 
#define mod 1000000009
#define eps 1e-10
template <typename T>
inline void read(T& X) {
	X = 0; int w = 0; char ch = 0;
	while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
	while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
	if (w) X = -X;
}
int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	ll n,l,k;
	ll p,w;
	cin>>l>>n>>k;
	if(k==1){
		printf("0");
		return 0;
	}
	ll ans=0;//当前走的步数 
	ll now=n;//剩下的粮食 
	ll tang; //当前走一步要搬运的趟数 
	ll temp;
	tang=(now-1)/k+1;
	while(tang>1){
		tang=(now-1)/k+1;
		if(tang==1)break;
		temp=(tang-1)*k;
		if(ans+(now-temp)/(2*tang-1)>=l){
			now=now-(l-ans)*(2*tang-1);
			printf("%lld",now);
			return 0;
		}
		ans=ans+(now-temp)/(2*tang-1);
		if((now-temp)%(2*tang-1)==0){
			now=temp;
			continue;
		}
		else{
			now=now-(now-temp)/(2*tang-1)*(2*tang-1);
			if(now>=temp+2){//剩下的值大于2,则次数不变 
				now=now-(2*tang-1);
			}
			else{
				now=temp-(2*(tang-1)-1);//小于2的时候,舍弃。次数减一 
			}
			ans++;
		}
	}
	ll sy=l-ans;//趟数等于1,计算剩余的步数。 
	if(now>sy)printf("%lld",now-sy);
	else printf("0");
    return 0;
}

F GCD and LCM

题意:求有多少长度为 n n n的数列使得 g c d = a gcd=a gcd=a l c m = b lcm=b lcm=b

题解:显然,当 b b b% a a a!=0时,答案为0。
b b b% a a a==0时,我们可以把问题转化为 g c d = 1 gcd=1 gcd=1 l c m = b / a lcm=b/a lcm=b/a
c c c= b b b/ a a a,由于 g c d gcd gcd=1,我们可以把 c c c分解成素数来考虑。
对于每一个素数来说,假设 c c c中存在 k k k个素数 s s s,那么在 n n n个数中,必须有一个为1,来保证 g c d gcd gcd=1,同理必须有一个 s k s^k sk,来保证 l c m lcm lcm= s k s^k sk
此时,所有素数相乘 g c d = 1 gcd=1 gcd=1 l c m = b / a lcm=b/a lcm=b/a
所以我们只需要对每一个素数进行容斥。算出有一个 1 1 1,一个 s k s^k sk的组合有多少种,最后累乘即可。
注意这题 m o d = 1 e 9 + 9 mod=1e9+9 mod=1e9+9,赛时 m o d mod mod取了 1 e 9 + 7 1e9+7 1e9+7wa了5发。。。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
using namespace std;
#define ll long long
#define maxn 100100 
#define mod 1000000009
#define eps 1e-10
template <typename T>
inline void read(T& X) {
	X = 0; int w = 0; char ch = 0;
	while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
	while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
	if (w) X = -X;
}
ll a[11111];
ll k=0;
void cel(ll n)
{
    int i,c;
    memset(a,0,sizeof a);
    for(i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            c=0;
            while(n%i==0)
            {
                c++;
                n/=i;
            }
            a[k++]=c;
        }
    }
    if(n>1){
    a[k++]=1;
}
}
ll q_pow(ll x,ll y){
	if(x==0)return 0;
	ll ans=1;
	while(y){
		if(y%2==1){
			y--;
			ans=ans*x%mod;
		}
		else {
			y/=2;
			x=x*x%mod;
		}
	}
	return ans%mod;
}
int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	ll w,b,c;
	cin>>w>>b>>c;
	if(c%b){
		cout<<"0";
	}
	else{
		c=c/b;
		cel(c);
		ll ans=1;
		ll q=w%mod*(w-1)%mod;
	for(int i=0;i<k;i++){
		ans=ans*(q_pow(a[i]+1,w)%mod-(2*q_pow(a[i],w))%mod+q_pow(a[i]-1,w)%mod)%mod;
		ans=(ans+mod)%mod;
	}
		cout<<ans;
	}
    return 0;
}

G Pots

题意:n个花盆,小的可以放在大的里面,问最后剩下几个花盆.
题解:签到题。算出同大小花盆的最大数量即可。

H Messenger

题意:每次选择一个位置 x x x ,翻转子串 s [ 1 ⋯ x ] s[1\cdots x] s[1x] 和子串 s [ ( x + 1 ) ⋯ ∣ s ∣ ] s[(x+1)\cdots |s|] s[(x+1)s] ,求进行 n n n 次操作以后的状态。

题解:如果把字符串看作一个环的话,每次操作其实就是环的翻转以及起点的变化。
环的翻转只需要根据总操作次数的奇偶性判断即可,起点的变化,每次暴力处理即可。(输入为一行,赛时因为没注意到有空格wa了3发)

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
using namespace std;
#define ll long long
#define maxn 100100 
#define mod 1000000007
#define eps 1e-10
template <typename T>
inline void read(T& X) {
	X = 0; int w = 0; char ch = 0;
	while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
	while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
	if (w) X = -X;
}
string s;
int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int n,k=1,x,ans=0;
	getline(cin,s);
	int len=s.length();
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>x;
		if(x>=k){
			k=(1+x)-k;
		}
		else {
			k=x+1+len-k;
		}
	}
	if(n%2){
		int p=0;
		for(int i=k-1;i>=0;i--){
			cout<<s[i];
		}
		for(int i=len-1;i>=k;i--){
			cout<<s[i];
		}
	}
	else{
		for(int i=0;i<k-1;i++){
			cout<<s[len-k+i+1];
		}
		int p=0;
		for(int i=k-1;i<len;i++){
			cout<<s[p++];
		}
	}
    return 0;
}

I Manhattan Project

题意:支持加点、删点、和询问和一个点的曼哈顿距离最远的距离。

题解:四维的曼哈顿距离可以用类似二维的方式进行切比雪夫转换。

也就是转换成 m a x { ± x 1 ± x 2 ± x 3 ± x 4 ± y 1 ± y 2 ± y 3 ± y 4 } max\{\pm x_1\pm x_2\pm x_3\pm x_4\pm y_1\pm y_2\pm y_3\pm y_4\} max{±x1±x2±x3±x4±y1±y2±y3±y4}
用十六个优先队列分别维护 ± \pm ± 的十六种情况即可。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
using namespace std;
#define ll long long
#define maxn 100100 
#define mod 998244353
#define eps 1e-10
template <typename T>
inline void read(T& X) {
	X = 0; int w = 0; char ch = 0;
	while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
	while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
	if (w) X = -X;
}
struct node{
	int x[4];
	bool operator < (const node&a)const{
	for(int i=0;i<4;i++){
		if(x[i]!=a.x[i])return x[i]<a.x[i];
	}
	return false;
	}
};
int n;
set<node>se;
priority_queue< pair<int,node> >q[16];

int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin>>n;
	node nex;
	int k;
	for(int i=1;i<=n;i++){
		cin>>k>>nex.x[0]>>nex.x[1]>>nex.x[2]>>nex.x[3];
		if(k==1){
			se.insert(nex);
			for(int i=0;i<16;i++){
				int w=0;
				for(int j=0;j<4;j++){
					if(i&(1<<j))w+=nex.x[j];
					else w-=nex.x[j];
				}
				q[i].push(make_pair(w,nex));
			}
		}
		else if(k==2){
			se.erase(nex);
		}
		else {
			int numm=0;
			for(int i=0;i<16;i++){
				int num=0;
			while(!q[i].empty()){
				node ans=q[i].top().second;
				if(!se.count(ans)){
					q[i].pop();
				}
				else{
					for(int i=0;i<4;i++){
						num+=abs(ans.x[i]-nex.x[i]);
					}
					numm=max(numm,num);
					break;
				}
			}
		}
		cout<<numm<<endl;
		}
	}
    return 0;
}
 

M The smallest fraction

题意:求 n n n 个分数的最小公倍数。
题解:分别维护分子,分母。分子是所有分子的最小公倍数,分母是所有分母的最大公约数,最后约分。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
using namespace std;
#define ll long long
#define maxn 100100 
#define mod 998244353
#define eps 1e-10
template <typename T>
inline void read(T& X) {
	X = 0; int w = 0; char ch = 0;
	while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
	while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
	if (w) X = -X;
}
int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	long long n,a,b,ansa=1,ansb=1;
	cin>>n;
	cin>>a>>b;
	ansa=a;ansb=b;
	for(int i=2;i<=n;i++){
		cin>>a>>b;
		ansb=__gcd(ansb,b);
		ansa=a*ansa/__gcd(ansa,a);
	}
	cout<<ansa/__gcd(ansa,ansb)<<" "<<ansb/__gcd(ansa,ansb);
    return 0;
}
 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值