文章目录
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[1⋯x] 和子串 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;
}