2018ICPC焦作

A-Xu Xiake in Henan Province

简单的输入输出模拟

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef pair<int,int>P;
typedef long long ll;
int n;
int a,b,c,d;
int main()
{
   
    scanf("%d",&n);
    while(n--)
    {
   
        scanf("%d%d%d%d",&a,&b,&c,&d);
        int cnt=0;
        if(a>0)cnt++;
        if(b>0)cnt++;
        if(c>0)cnt++;
        if(d>0)cnt++;
        if(cnt==0)
            printf("Typically Otaku\n");
        else if(cnt==1)
            printf("Eye-opener\n");
        else if(cnt==2)
            printf("Young Traveller\n");
        else if(cnt==3)
            printf("Excellent Traveller\n");
        else
            printf("Contemporary Xu Xiake\n");
    }
}

B-Ultraman vs. Aodzilla and Bodzilla

C-Supreme Command

D-Keiichi Tsuchiya the Drift King

题意:

已知小圆半径r,小圆两个最两边半径的夹角d,车的宽和长分别为a,b,与直道与圆相切,要求小车从从外面往园内开的时候右上角要与小圆相切,问:路的宽度至少为多少时车才不会开出马路。

这题最主要的是画图,主要是图清楚了,式子也就出来了。

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef pair<int,int>P;
typedef long long ll;
const double PI=acos(-1);
int t,a,b,r,d;
int main()
{
   
    scanf("%d",&t);
    while(t--)
    {
   
        scanf("%d%d%d%d",&a,&b,&r,&d);
        double fi=asin((a+r)/sqrt((a+r)*(a+r)+b*b));
        double th=d*PI/180.0;
        double res=sqrt((a+r)*(a+r)+b*b);
        if(fi<=PI/2.0&&fi+th>=PI/2.0)
            res-=r;
        else
            res=res*max(sin(fi),sin(fi+th))-r;
        printf("%.12f\n",res);

    }
}

E-Resistors in Parallel

题意:

多组样例,已知电阻的个数为n,让你求一堆电阻并联后电阻的阻值最小为多少。
以下公式题目已经给出:
并联电阻求阻值

对于每个电阻R的阻值的设定

对于一个集合i中存在电阻j的要求

solution

JAVA大数模拟+部分数学

先将电阻的求解转换为如下公式

对于下面这个式子,我的理解就是如果i=1,那么R1=1,其余情况则是在一堆素数里选择任意个素数连乘(每个素数只能选择一次)

因为要得到合并后的电阻尽可能小,那么我们就可以贪心的得到最大的电阻Rk为从2开始连续个素数相乘不超过n,因为Rk是阻值最大且满足条件的一个电阻,所以我们可以知道其余比Rk小的电阻的阻值就是从Rk中一堆连乘的素数中挑一些来相乘后得到的值。
那么R的分母就是一堆素数去或者不取进行dp求和就可以了

dp[i]=dp[i-1]*p[i]+dp[i-1]

import java.math.BigInteger;
import java.util.Scanner;
import java.util.Stack;
public class Main{
   
	static BigInteger sum;
	static int k;
	static int[] prime=new int[1000006];
	static BigInteger x;
	public static void main(String[] args) {
   
		
		Scanner in=new Scanner(System.in);
		int t=in.nextInt();
		int cnt=0;
		int[] vis= new int[1000006];
		for(int i=2;i<=100000;i++) {
   
			if(vis[i]==0) {
   
				prime[cnt++]=i;
				for(int j=i;j<=100000;j+=i) {
   
					vis[j]=1;
				}
			}
		}
 		while(t>0) {
   
			BigInteger n=in.nextBigInteger();
			x=BigInteger.valueOf(1);
			if(n.compareTo(BigInteger.valueOf(1))==0) {
   
				System.out.println("1/1");
				t--;
				continue;
			}
			k=-1;
			for(int i=0;i<cnt;i++) {
   
				if(x.multiply(BigInteger.valueOf(prime[i])).compareTo(n)<=0) {
   
					x=x.multiply(BigInteger.valueOf(prime[i]));
					k=i;
				}else {
   
					break;
				}
			}
			sum=BigInteger.valueOf(1);
			for(int i=0;i<=k;i++)
				sum=sum.multiply(BigInteger.valueOf(prime[i]+1));
			BigInteger z=sum.gcd(x);
			System.out.println(x.divide(z)+"/"+sum.divide(z));
			t--;
		}
	}
}

F-Honeycomb

这题就是一般的宽度优先遍历,只不过坐标有点麻烦。
但是我RE了好多次,因为漏打了个括号(所以敲代码的时候一定要仔细!!!!!!)

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef pair<int,int>P;
typedef long long ll;
char tu[8005][8005];
int n,r,c;
int cnt[80005];
int sx,sy,tx,ty;
int dx[]={
   1,-1,1,-1,2,-2},dy[]={
   3,3,-3,-3,0,0};
int bfs()
{
   
    map<P,int> d;
    d[P(sx,sy)]=1;
    queue<P> q;
    q.push(P(sx,sy));
    while(!q.empty())
    {
   
        P p=q.front();q.pop();
        int now=d[P(p.first,p.second)];
        for(int i=0;i<6;i++)
        {
   
            int xx=p.first+dx[i],yy=p.second+dy[i];
            if(xx<0||xx>=4*r+3||yy<0||yy>=cnt[xx])continue;
            if(tu[xx][yy]!=' ')continue;//cout<<xx<<' '<<yy<<endl;
            xx+=dx[i],yy+=dy[i];
            if(xx<0||xx>=4*r+3||yy<0||yy>=cnt[xx])continue;
            if(d[P(xx,yy)]!=0)continue;
            d[P(xx,yy)]=now+1;
            q.push(P(xx,yy));
        }
    }
    if(d[P(tx,ty)]==0)return -1;
    else return d[P(tx,ty)];
}
int main()
{
   
    scanf("%d",&n);
    while(n--)
    {
   
        scanf("%d%d",&r,&c);getchar();
        for(int i=0;i<4*r+3;i++)
        {
   
            gets(tu[i]);
            cnt[i]=strlen(tu[i]);
            for(int j=0;j<6*c+3;j++)
            {
   
                if(tu[i][j]=='S')sx=i,sy=j;
                if(tu[i][j]=='T')tx=i,ty=j;
            }
        }
        printf("%d\n",bfs());
    }
}

G-Shortest Paths on Random Forests

H-Can You Solve the Harder Problem?

I-Distance

题意:

多组样例,给了你n个点,n-1个相邻两点之间的距离,选的点的个数从1到n,求选i个点的任意两点距离之和的最大值是多少

solution:

轮流从两边选取点,从最外层开始。在这种情况下贪心是最优的。

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef pair<int,int>P;
typedef long long ll;
const double PI=acos(-1);
int n;
ll a[100005];
ll res[100005];
ll sum[100005];
int t;
int main()
{
   
    scanf("%d",&t);
    while(t--)
    {
   
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
   
            scanf("%lld",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        res[1]=0;
        int cnt=0;
        ll pre=0;
        for(int i=2;i<=n;i++)
        {
   
            res[i]=res[i-1]+sum[n-cnt-1]-sum[cnt]+pre;
            if(i%2){
   pre+=sum[n-cnt-1]-sum[cnt];cnt++;}
        }
        printf("%lld",res[0]);
        for(int i=2;i<=n;i++)
            printf(" %lld",res[i]);
        printf("\n");
    }
}

J-Carpets Removal

K-Counting Failures on a Trie

L-Connected Subgraphs