2017 沈阳区域赛部分题解

A - BBP Formula HDU - 6217

题意:给了 π 的BBP近似公式,求出来的是10进制值,问如果用16进制表示 π 的小数点后第n位是啥

分析:典型的BBP问题tl
我们可以从这个公式中得出,可以先乘 16n1 ,小数部分求出来,然后小数部分再乘16,这个整数部分就是我们的答案。
为什么不直接乘 16n ,然后答案就是整数部分mod16…emmm,这个给你们根据式子想想~

#include
using namespace std;
typedef long long ll;
int n;
ll qm(ll a,int n,int mod)
{
    ll ans = 1 ;
    while(n)
    {
        if(n&1) ans  = ans*a%mod;
        a = a*a%mod;
        n>>=1;
    }
    return ans%mod;
}
double BBP(int n,int t)
{
    double ans = 0;
    for(int i=0;i<=n;i++)
        ans +=(double)qm(16,n-i,t+8*i)/(t+8*i);
    for(int i=n+1;i<=n+1000;i++)
        ans +=pow(16,n-i)/(8*i+t);
    return ans;
}
int main()
{
    int T,case1=1;;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        n--;
        double ans = 4*BBP(n,1)-2*BBP(n,4)-BBP(n,5)-BBP(n,6);
        //cout<//cout<<(int)ans<int)ans;
        if(ans<0) ans+=1;
        ans = ans*16;
        int t =(int)ans;
       // cout<printf("Case #%d: %d ",case1++,n+1);
        if(t>=0&&t<=9) printf("%c\n",t+'0');
        else printf("%c\n",t-10+'A');
    }
    return 0;
}

F - Heron and His Triangle HDU - 6222

题意:三个连续的整数t-1,t,t+1,组成三角形,并且三角形的面积是整数。问不小于n的t值是多少

分析:因为这个t是不会大的。直接用java,打表找规律~
(我开始还化简了好久,,然后再打的..真应该直接无脑打个先看看..

import java.math.BigInteger;
import java.util.Scanner;

public class Main{
    public static void main(String[] args) {
        BigInteger[] a = new BigInteger[105];
        BigInteger x = new BigInteger("4");
        BigInteger y = new BigInteger("14");
        a[0] = x;a[1]= y;
        int id = 2;
        BigInteger lim = BigInteger.TEN.pow(30);
        while(y.compareTo(lim)<=0)
        {
            BigInteger k = new BigInteger("4");
            BigInteger t = k.multiply(y).subtract(x);
            x = y;
            y = t;
            a[id++] = y;
        }
        Scanner in = new Scanner(System.in);
        int t;
        t = in.nextInt();
        BigInteger n;
        while(t-->0)
        {
            n = in.nextBigInteger();
            int i=0;
            y = a[i];
            while(y.compareTo(n)<0)
            {
                i++;
                y = a[i];
            }
            System.out.println(a[i]);
        }
    }
 }

G - Infinite Fraction Path HDU - 6223

题意:给一个串,长度为n,由0-9,10个数字组成。有一个转移规律,下标为i下一步会转移到(i*i+1)%n的位置上。问从一个点开始,走转移n-1步,走过的路径(为经过位置的值)字典序最大的是啥

分析:….
直接将最大值入队,
然后对于每一层,如果这一步走的值不是最大的,那么就删去
如果这一层中有下标相同的也可以删去

(这个思想过了,但是wo还是不能证明为什么这个暴力不会超时..
(队友说还有后缀数组的方法,下次问他之后再加上~

#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
const int maxn = 150100;
char str[maxn];
int s[maxn],ans[maxn],vis[maxn];
ll zy[maxn];
struct node{
    ll id;int step,z;
};
struct compare
{
    bool operator()(const node &a,const node &b) const   //ans最小值优先 权值最大值优先
    {
        if(a.step!=b.step) return a.step>b.step;
        else if(a.z!=b.z) return a.zreturn a.id>b.id;
    }
};
priority_queuevector,compare > q;

int main()
{
    int T,case1=1;
    scanf("%d",&T);
    while(T--)
    {
        while(!q.empty()) q.pop();
        int n,maxx=0;
        scanf("%d",&n);
        scanf("%s",str);
        mem(ans,-1);mem(vis,-1);mem(s,0);
        for(int i=0;i'0';maxx=max(maxx,s[i]);zy[i]=((ll)i*(ll)i+1ll)%(ll)n;}
        for(int i=0;iif(s[i]==maxx) {node a;a.id=i;a.z=s[i];a.step=0;q.push(a);}
        while(!q.empty())
        {
            node t = q.top();q.pop();
            if(t.step==n) continue;
            if(ans[t.step]==-1) ans[t.step] = t.z;
            else if(ans[t.step]<=t.z) ans[t.step]=t.z;
            else continue;
            if(vis[t.id]else continue;
            ll tmp = zy[t.id];
            node a1;a1.id = tmp;a1.z=s[tmp];a1.step=t.step+1;
            q.push(a1);
        }
        //printf("Case #%d: ",kase++);
        printf("Case #%d: ",case1++);
        for(int i=0;iprintf("%d",ans[i]);
        printf("\n");
    }
    return 0;
}

I - Little Boxes HDU - 6225

题意:给四个数,问四个数加起来的值

分析:用java真是方便。因为数据范围有点大,然后用longlong会爆掉,然后用double卡下精度也失败了。然后就只能大数了~

L - Tree HDU - 6228

题意:给一棵树,给k种不同颜色去涂这树上的节点,Ei表示用第i种颜色涂的节点连起来的最小边集。问E1 E2 E3 Ek的最大值

分析:就是统计哪些点的(孩子个数+1)和(父亲个数+1)(除去孩子个数)>=(k),然后答案就是这些点的数量。+1表示加上自己~

using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn = 200010;
struct node{
   int to,pre;
}e[maxn*2];
int head[maxn],h=0,vis[maxn],num[maxn];
void init()
{
    mem(vis,0);mem(head,-1);mem(num,0);h=0;
}
int addedge(int from,int to)
{
    e[h].to=to;e[h].pre = head[from];head[from]=h;h++;
}
void dfs(int u)
{
    vis[u]=1;num[u]=1;
    for(int i=head[u];i>-1;i=e[i].pre)
    {
        int v = e[i].to;
        if(vis[v]) continue;
        dfs(v);
        num[u]+=num[v];
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        init();
        int n,k;
        scanf("%d %d",&n,&k);
        for(int i=0;i1;i++)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            addedge(x,y);addedge(y,x);
        }
        dfs(1);
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            if(num[i]>=k&&(n-num[i])>=k) ans++;
        }
        printf("%d\n",ans);
    }
}

M - Wandering Robots HDU - 6229

题意:在一个n*n网格中,有一个机器人,然后每个单位时间,它可能有5种操作,向上,下,左,右走,不动。有k个障碍物在网格中,当然它不能走出网格,以及走到障碍物的格子中。问它可能在x+y>=(n-1)的概率是多少。
(x,y)为坐标,x,y [0,n-1]

题解:找规律?
来看第一个样例
n=3,k=0;
每个格子的可能性为
3 4 3
4 5 4
3 4 3
ans=(33-11)/33;
第二个样例
n=3,k=1;
障碍物:(1,1)
每个格子的可能性为
3 3 3
3 0 3
3 3 3
ans=(24-9)/24=5/8;

然后验证一下后面的例子,发现答案…
模拟一下就行了

using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn = 150;
int dp[maxn][maxn][maxn];
int sum[maxn];
int gcd(int a,int b)
{
    if(b==0) return a;
    else return gcd(b,a%b);
}
int main()
{
    int T,cas = 1;
    scanf("%d",&T);
    while(T--)
    {
        int n,k;
        set<int> Set;
        scanf("%d %d",&n,&k);
        int sum=1,a=0;
        if(n<=0)  {printf("Case #%d: %d/%d\n",cas++,sum-a,sum);continue;}
        if(n>1){
            sum = 5*n*n-2*4-4*(n-2);
            a = 3+8*(n-2)+(n-2)*(n-3)/2*5;
        }
        for(int i=0;iint x,y;
            scanf("%d %d",&x,&y);
            int temp = x*n+y,b=0;
            if(Set.count(temp)) continue;
            else {
                Set.insert(temp);
                int tmp=0;
                if(temp>=n) {b++;tmp=temp-n;if(Set.count(tmp)==0) {sum--;if(x-1+y<(n-1))a--;}else b--;}
                if(temp1)) {b++;tmp=temp+n;if(Set.count(tmp)==0){sum--;if(x+1+y<(n-1)) a--;}else b--;}
                if(temp%n>0) {b++;tmp=temp-1;if(Set.count(tmp)==0) {sum--;if(x+y-1<(n-1)) a--;}else b--;}
                if(temp%n<(n-1)) {b++;tmp=temp+1;if(Set.count(tmp)==0){sum--;if(x+y+1<(n-1))a--;}else b--;}
                sum-=(b+1);if(x+y<(n-1)) a-=(b+1);
            }
        }
        int t=1;
        if(sum!=0)t=gcd(sum-a,sum);
        printf("Case #%d: %d/%d\n",cas++,(sum-a)/t,sum/t);
    }
    return 0;
}
/*
5
5 4
1 1
1 2
2 3
3 2
*/

你可能感兴趣的:(contests)