“Wishare杯”南邮第八届大学生程序设计竞赛之网络预赛 题解报告

帅神妹纸的生日礼物

时间限制(普通/Java):1000MS/3000MS         运行内存限制:65536KByte

比赛描述

    A协大牛帅神的妹纸最近又要过生日了,然而妹纸心里早已有一个想要的礼物,妹纸想要的礼物就是10种稀有的钻石,帅神为了满足妹纸的要求,四处打探知道了钻石在一个神秘的地方,这个地方有很多神,所有神灵站成一排,每个神手上有一种钻石,然而懒虫帅神为了少走路,想着尽可能少的访问相邻神,从他们手中获得钻石,已知妹纸对于每种钻石需求的数量多少,求问帅神需要最少访问多少连续的神才可以获得妹纸需要钻石。


输入

本题为多组样例,第一行输入一个整数t(t <= 100),表示样例个数,对于每组样例,

第一行为一个由0-9数字组成的字符串组成(长度小于100,000),表示站成一排的神灵,每种数字代表该神拥有几号钻石

第二行为10个数字,分别表示妹纸需要的0-9号钻石是多少


输出

每组样例输出一个数字,表示最少访问多少个连续的神可以满足妹纸需求,如果无法满足,输出"Let's break up"。


样例输入

2
1234567890
0 0 0 1 1 0 1 0 0 0
1234567890
2 0 0 0 0 0 0 0 0 0


样例输出

4
Let's break up


题目分析:典型的两点法,用st和ed维护一段区间,先找第一段符合条件的,然后缩小范围判断,不满足了再往后扩大范围

#include 
#include 
#include 
using namespace std;
int const MAX = 100005;
int const INF = 0x3fffffff;
int need[15], has[15];
char s[MAX];

bool judge()
{
    for(int i = 0; i < 10; i++)
        if(has[i] < need[i])
            return false;
    return true;
} 

int main()
{
    int T;
    scanf("%d", &T);
    while(T --)
    {   
        memset(has, 0, sizeof(has));
        scanf("%s", s);
        int len = strlen(s);
        for(int i = 0; i < 10; i++)
            scanf("%d", &need[i]);
        int st = 0, ed = 0, ans = INF;
        while(ed < len)
        {
            while(!judge() && ed < len)
            {
                has[s[ed] - '0'] ++;
                ed ++;
            }
            while(judge() && st < ed)
            {
                ans = min(ans, ed - st);
                has[s[st] - '0'] --;
                st ++;
            }
        }
        if(ans == INF)
            printf("Let's break up\n");
        else
            printf("%d\n", ans);
    }   
}

玛德之杖

                                                         时间限制(普通/Java):1000MS/3000MS         运行内存限制:65536KByte

比赛描述

    玛德士是世界上数一数二的制杖大师,他用自己的名字命名了自己的得意之作,称呼那柄法杖为“玛德之杖”。数百年后你得到了这柄法杖,但是你却无法使用它,你从一篇密录上知道只有求出法杖上每个数的各个数位之和,才能将其掌控。你能成功吗?


输入

第一行T,是测试数据的数量。T<=100

以下T行,每行一个整数a,0


输出

每组数据输出一行,为a的各个数位之和。


样例输入

3
10
199
2333

样例输出

1
19
11


题目分析:没啥好说

#include 

int main()
{
    int T;
    scanf("%d", &T);
    while(T --)
    {
        int n, ans = 0;
        scanf("%d", &n);
        while(n)
        {
            ans += n % 10;
            n /= 10;
        }
        printf("%d\n", ans);
    }
}


小明的排队

                                                         时间限制(普通/Java): 2000MS/6000MS         运行内存限制:65536KByte

比赛描述

    TC是个土豪,经常给整个集训队发苹果,并且喜欢将大家排成一队根据每个人的苹果数量做出一些奇怪的事情,比如让每个人算出自己右边苹果数量比自己少的人的个数。拿别人的手短,大家对于TC的奇怪嗜好也只能牵就了。


输入

输入第一行为一个T(T <= 6)表示数据组数,每组数据包含整数n(n个人, 1<=n<=100000),以及n个整数(正整数,代表每个人相应的苹果数量)


输出

对于每组数据输出n个整数,第i个整数表示第i个人右边苹果比他的少的人的个数。


样例输入

1
4 5 2 6 1


样例输出

2 1 1 0


提示

输入请用scanf,输出请用printf

输出数据的最后一个数字后面也有空格


题目分析:典型的逆序数问题,归并排序和树状数组都可以做

#include 
#include 
int const MAX = 1e5 + 5;
int const INF = 0x7FFFFFFF;
int n, a[MAX], res[MAX];

struct DATA
{
    int val, idx;
}d[MAX], a1[MAX], a2[MAX];
    
void merge_sort(int l, int mid, int r, DATA *d) 
{
    int len1 = mid - l;
    int len2 = r - mid;
    for(int i = 0; i < len1; i++)
        a1[i] = d[i + l]; 
    a1[len1].val = INF;
    for(int i = 0; i < len2; i++) 
        a2[i] = d[i + mid]; 
    a2[len2].val = INF;
    int i = 0, j = 0, k = l, tmp = 0;
    while(i < len1 || j < len2) 
    {
        if(a1[i].val <= a2[j].val) 
        {
            res[a1[i].idx] += tmp;
            d[k ++] = a1[i ++];         
        }
        else 
        {
            if(a1[i].val != INF) 
                tmp ++;
            d[k ++] = a2[j ++];         
        }
    }
}

void Merge(int l, int r, DATA *d) 
{
    if(l == r - 1) 
        return; 
    int mid = (l + r) >> 1;
    Merge(l, mid, d);
    Merge(mid, r, d);
    merge_sort(l, mid, r, d);
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T --)
    {
        memset(res, 0, sizeof(res));
        scanf("%d", &n);
        for(int i = 0; i < n; i++)
            scanf("%d", &a[i]);
        for(int i = 0; i < n; i++) 
        {
            d[i].val = a[i]; 
            d[i].idx = i;
        }
        Merge(0, n, d);
        for(int i = 0; i < n; i++)
            printf("%d ", res[i]);
        printf("\n");
    }
}

Money

时间限制(普通/Java): 1000MS/3000MS         运行内存限制:32768KByte

比赛描述

    土豪BJ当前身上有现金x元,为了接济他的穷diao基友Tc,他对Tc说你现在可以交换我当前现金的任意两个相邻数字最多k次,多出来的钱都给你,Tc想知道自己最多能得到多少现金。


输入

输入第一行为一个整数T代表数据组数,每组数据只有一行包括两个数字x和k,数字均不含前导零

(1 <= T <= 15, 1 <= x <= 1019, 0 <= k <= 100)


输出

对每组数据,输出一个数字表示Tc能得到的最多现金数。


样例输入

3
1399 3
256 1
109009 4


样例输出

7920
270
801891

题目分析:尽量让高位的数字大,从最高位开始向低位找,先找到k步之内的最大数,如果k步之内的最大数不是当前位置的数,那么把最大数交换到当前为止,然后减去初始值即可,因为没有负数,可以直接I64u

#include   
#include   
#include 
#define ull unsigned long long  
using namespace std;
char s[20];  
int k;  
  
int main()  
{  
    int T;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%s %d", s, &k);
        ull bj_cash, tc_cash;
        sscanf(s, "%I64u", &bj_cash);
        int len = strlen(s), now;    
        for(int i = 0; i < len; i++)  
        {  
            now = i;  
            for(int j = i + 1; j <= i + k && j < len; j++)  
                if(s[j] > s[now])  
                    now = j;  
            if(now != i)  
            {  
                for(int j = now; j > i; j--)  
                {  
                    swap(s[j], s[j - 1]);  
                    k --; 
                } 
             }    
        }
        sscanf(s, "%I64u", &tc_cash);
        printf("%I64u\n", tc_cash - bj_cash);  
    }  
} 



简单的序列

时间限制(普通/Java): 1000MS/3000MS         运行内存限制:65536KByte

比赛描述

    按照下列规则生成一个序列,当x > 0时 A[x] = A[x-1] xor x,当x == 0时,即A[0] = 0,现给出一个n,求序列的第n项。


输入

第一行一个数字T,有T组数据(T<=100000),接下来T行,每行一个数字n  (n<=100000)


输出

T行,每行输出序列的第n项


样例输入

3
1
2
3

样例输出

1
3
0

题目分析:没啥好说

#include 
int a[100005];

void pre()
{
    a[0] = 0;
    for(int i = 1; i <= 100000; i++)
        a[i] = (a[i - 1] ^ i);
}

int main()
{
    pre();
    int T, n;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d", &n);
        printf("%d\n", a[n]);
    }
}


有趣的区间异或值

时间限制(普通/Java): 2000MS/6000MS         运行内存限制:65536KByte

比赛描述

按照下列规则生成一个序列,当x > 0时 A[x] = A[x-1] xor x,当x == 0时,即A[0] = 0,当然,题目没有这么简单,有n组查询,对于每组询问L,R,就要输出序列A[L] xor A[L+1] xor A[L+2]...xor A[R-1] xor A[R],即这个序列下标在[L,R]区间内的异或值。


输入

第一行一个数字N,表示N组询问(N <= 105),接下来N行,第i行给出第i组询问的L,R(1<=L<=R<=109)


输出

输出N行,每行一个数,即序列下标在[L,R]区间内的异或值


样例输入

4
1 5
2 8
3 10
10 100

样例输出

7
9
0
111

题目分析:打个小表,可以找到两个规律,首先对于前缀异或和有个周期为4的规律,对于前缀异或和的前缀异或和有个周期为8的规律,然后求a[l] ^ a[l + 1] ^ ... ^ a[r - 1] ^ a[r],根据异或的性质a^a=0,a^0=a,所以相当于求(a[0] ^ a[1] ^ ... ^ a[l]) ^ (a[0] ^ a[1] ^ ... ^ a[r]),因此直接找规律算算即可

打表:

#include 
int a[55];
int sum[55];

int main()
{
    a[0] = 0;
    for(int i = 1; i <= 55; i++)
    {
        a[i] = a[i - 1] ^ i;
        printf("a[%d] = %d\n", i, a[i]);
    }
    sum[0] = 0;
    for(int i = 1; i <= 55; i++)
        sum[i] = sum[i - 1] ^ a[i];
    printf("sum[5] = %d\n", sum[5]);
    for(int j = 0; j < 50; j++)
        printf("i = 0 j = %d ans = %d\n", j, sum[0] ^ sum[j]);         
}

然后~
#include   
      
int solve(int x)  
{  
    if(x % 8 == 0 || x % 8 == 1)  
        return x;  
    if(x % 8 == 2 || x % 8 == 3)  
        return 2;  
    if(x % 8 == 4 || x % 8 == 5)  
        return x + 2;  
    return 0;  
}  
      
int main()  
{  
    int T;  
    scanf("%d", &T);  
    while(T --)  
    {  
        int l, r;  
        scanf("%d %d", &l, &r);  
        printf("%d\n", (solve(r) ^ solve(l - 1)));  
    }     
}  


Single or Single ?

时间限制(普通/Java): 1000MS/3000MS         运行内存限制:65536KByte

比赛描述

    妹子终于答应和BJ交往了,但有个前提,BJ必须进入一个有电梯的魔法大楼接受考验,假设大楼有无数层,BJ开始被关在第n层的电梯中,电梯每次有三种移动方式,上升一层,下降一层,从第i层直接上升到第2i层,每次移动都需要1分钟的时间,只有层数为素数的楼层电梯门才可以打开,门打开BJ就可以出来了,妹子只给了他k分钟,规定时间内BJ能出来则可以带走妹子过上幸福的生活,否则他就注孤了,单身已久的BJ当然是希望尽快出来。


输入

第一行包含一个整数T代表数据组数,每组数据有两个数字n和k

(1 <= T <= 50,1 <= n <= 107,0 <= k <= 20)


输出

如果BJ可以在规定时间内出来,则输出BJ gets the pretty meizi with x minutes! (x为BJ出电梯的最快时间),否则输出Poor BJ, single all his life!

样例输入

3
6 0
26 2
10 1


样例输出

Poor BJ, single all his life!
BJ gets the pretty meizi with 2 minutes!
BJ gets the pretty meizi with 1 minutes!

题目分析:裸的BFS,打表可以发现,这个数据量6步之内必有解,因此暴力枚举其实也可以,又因为步数少,判断素数的时候直接找因子,不用预处理素数筛

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
map  vis;
int n, k;

struct POINT
{
    int num, step;
};

bool judge(int x)
{
    if(x == 1 || x % 2 == 0)
        return false;
    for(int i = 3; i <= (int) sqrt(x); i += 2)
        if(x % i == 0)
            return false;
    return true;
}

int BFS()
{
    vis.clear();
    vis[n] = true;
    queue  q;
    POINT st;
    st.num = n;
    st.step = 0;
    q.push(st);
    while(!q.empty())
    {
        POINT cur, t;
        cur = q.front();
        q.pop();
        if(judge(cur.num))
            return cur.step;
        t.num = cur.num + 1;
        if(!vis[t.num])
        {
            vis[t.num] = true;
            t.step = cur.step + 1;
            q.push(t);
        }
        t.num = cur.num - 1;
        if(!vis[t.num])
        {
            vis[t.num] = true;
            t.step = cur.step + 1;
            q.push(t);
        }
        t.num = cur.num * 2;
        if(!vis[t.num])
        {
            vis[t.num] = true;
            t.step = cur.step + 1;
            q.push(t);
        }
    }
    return 0;
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d %d", &n, &k);
        int ans = BFS();
        if(ans <= k)
            printf("BJ gets the pretty meizi with %d minutes!\n", ans);
        else
            printf("Poor BJ, single all his life!\n");
    }
}


有套路的BoJie

                                               时间限制(普通/Java):1000MS/3000MS         运行内存限制:65536KByte

比赛描述

    BoJie是一位传说中把妹很有套路的男子。有一次BoJie请妹子喝奶茶,非常有心机地买了一杯大杯的,想与妹子共饮。可是身经百战的妹子居然掏出了两个大小不一的杯子。BoJie瞬间就傻眼了,套路被识破了。然而这还没有完,妹子说,你要用这三个杯子,将这一大杯奶茶平分为两份。BoJie终日打雁却被雁啄了眼。只能够向大家讨教,这件事,是否可行呢?然而巧合的是,妹子掏出的两个杯子容量之和正好是BoJie买的奶茶的容量。杯子均无刻度,三个杯子之间可以互相倒奶茶。


输入

第一行T,是测试数据的数量。T<=10000

以下T行,每行两个整数,分别为两个小杯子的容量a,b,其中0


输出

每个样例输出一行,如果可行,输出”YES”,如果不可行,输出“NO”


样例输入

2
10 20
3 15


样例输出

NO
YES

题目分析:其实是一个搜索题,但是卡搜索时间了,于是就可以安心找规律了

#include 

int Gcd(int a, int b)
{
    return b ? Gcd(b, a % b) : a;
}

int main()
{
    int T, a, b;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d %d", &a, &b);
        printf("%s\n", (((a + b) >> 1) % Gcd(a, b) == 0) ? "YES" : "NO");
    }
}


Dreaming

时间限制(普通/Java):4000MS/12000MS         运行内存限制:16384KByte

比赛描述

    BJ梦到自己被n个妹子围住,每个妹子对他有个好感度ai,他对这些妹子的吸引力被定义为位置连续的妹子对他好感度和的最大值,现在他想知道自己的吸引力是多少。


输入

第一行为一个数字T代表数据组数,每组数据的第一行为一个数字n表示妹子个数,下一行包含n个数,代表第i个妹子对他的好感度。

(1 <= T <= 5,1 <= n <= 2*106,|ai| <= 108,1 <= i <= n)


输出

每组数据输出一个数,代表BJ对该组妹子的吸引力。


样例输入

3
1
100000000
2
-1 1000
7
-1 1 -2 2 3 -1 5

样例输出

100000000
1000
9

提示

因为他被围住,所以a1和an位置上是相邻的。

连续的妹子数至少为1

输出用scanf, 输出用printf


题目分析:就是环形最大连续和,卡了空间,后来时间也放了,本题无需开数组,O(n)求一遍最大连续和x,O(n)再求一遍最小连续和y,设总和为sum,那么答案就是max(x, sum - y)

#include 
#define ll long long
int const INF = 2147483647;

int main()
{
	int T, n;
	scanf("%d", &T);
	while(T --)
	{
		scanf("%d", &n);
		ll val, ma = -INF, curma = 0, sum = 0, mi = INF, curmi = 0, tmp = -INF;
		bool f = false;
		for(int i = 0; i < n; i++)
		{
			scanf("%I64d", &val);
			if(val >= 0)
				f = true;
			if(tmp < val)
				tmp = val;
			sum += val;
			curma += val;
			if(curma > ma)
				ma = curma;
			if(curma < 0)
				curma = 0;
			curmi += val;
			if(curmi < mi)
				mi = curmi;
			if(curmi > 0)
				curmi = 0;
		}
		if(f)
			printf("%I64d\n", ma > sum - mi ? ma : sum - mi);
		else
			printf("%I64d\n", tmp);
	}
}


小明表达式

                                                                        时间限制(普通/Java) :1000MS/3000MS         运行内存限制:65536KByte

比赛描述

TC正在学习编译原理,自创了一套tc expression(小明表达式),(其实是正则表达式的子集)正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。

规则如下:

字母相同是匹配的

'.' 匹配任意的单个字符

'*' 匹配前一个字符0或无限次

匹配必须覆盖整个输入字符串(不是部分)


输入

包含T组数据

每组数据包含两个字符串长度均不超过20,第一个为目标串(仅包含大小写字母),第二个为正则表达式(仅包含大小写字母以及'.','*')


输出

如果匹配,输出true,否则输出false

样例输入

5
aa a
aa aa
aa a*
ab .*
aab c*a*b

样例输出

false
true
true
true
true

题目分析:比较不好做的一题,烦就烦在*可以匹配0次或任意多次,因为不知道具体几次,考虑用递归解决,我们可以把一个字符后面加个'*'的看做单独一组,若一个字符后面不是'*',那说明当前必须匹配,否则会失配,当前匹配有两种情况,1是字符值相等,2是正则式对应位置为'.'。若后一个是'*',则直接跳过这组,继续往后匹配,因为这样我们实际上就不用管具体要重复多少次了,这里递归的过程可能不是很好理解。。。

#include 
#include 
char s[25], t[25];
int lens, lent;

bool ok(int i, int j) 
{   
    if(j == lent) 
        return i == lens;
    if(t[j + 1] != '*')  
    {
        if((t[j] == s[i]) || (t[j] == '.' && i < lens))
            if(ok(i + 1, j + 1))
                return true;
        return false;  
    }
    while((t[j] == s[i]) || (t[j] == '.' && i < lens)) 
    {  
        if(ok(i, j + 2))  
            return true;  
        i ++;  
    }   
    if(ok(i, j + 2))  
        return true;  
    return false;
}  
int main()
{
    int T;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%s %s", s, t);
        lens = strlen(s);
        lent = strlen(t);
        printf("%s\n", ok(0, 0) ? "true" : "false");
    }
}




拯救活动室的男女比例

时间限制(普通/Java):2000MS/6000MS         运行内存限制:81920KByte

比赛描述

    为了拯救活动室的男女比例,队长kalili带着队员们连他一起共k人去说服妹子们努力学习算法加入A协大家庭,妹子们站成一个直角三角形,一共m行,第i行有i个妹子,每个妹子有一个颜值aij,规定每轮只能一个人来说服妹子且一人只能说服一轮,开始都面对第一个妹子,每说服完一个妹子只能往前或者往左走继续去说服别的妹子,如果遇到已经被说服的妹子则不用说服继续走,每个妹子最多被说服一次,现在已知A协的男精英们口才很好,不管颜值多高的妹子都能直接说服,求他们能说服的妹子们的总颜值最大是多少


输入

第一行一个整数T代表共T组样例,每组样例第一行包含两个数字m和k,接下来m行,第i行有i个数字表示对应妹子的颜值

(1 <= T <= 200,1 <= m <= 25, 0 <= k <= m,0 <= aij <= 108)

T >= 100的数据不超过五组

输出

对于每组样例,输出一个数字表示能说服的妹子们的最大总颜值


样例输入

2
2 1
1
1 2
3 2
1
2 3
4 5 6

样例输出

4
21

提示

对于第二组样例

第一个人可以以(1,1) -> (2,1) -> (2, 2) -> (3,2) -> (3,3)的顺序说服5个妹子

第二个人的顺序可以是(1, 1) -> (2, 1) -> (3, 1),因为(1,1) (2,1)位置的妹子已经被说服了,他这一轮只说服了一个妹子。

两轮下来所有妹子都被说服,因此总颜值就是她们的颜值和为21


题目分析:最大费用最大流,超源连起点,终点连超汇,费用为0,容量为k,有权值的点拆点键图,拆完点两条边一条费用为权值,容量为1保证取值,另一条费用为0,容量无穷大保证可重复走,然后跑个费用流~

#include 
#include 
#include 
#include 
#define ll long long
using namespace std;
int const INF = 0x3fffffff;
int const MAX = 26 * 26;
int n, k;
int head[MAX << 2], cnt;
int pre[MAX << 2], vis[MAX << 2];
int src, sk;
ll ans, a[30][30], dis[MAX << 2];

struct EGDE
{
    int to, nxt, cap;
    ll cost;
}e[MAX << 3];

void Init()
{
    ans = 0;
    src = 0;
    sk = 2 * n * n + 1; 
    cnt = 0;
    memset(head, -1, sizeof(head));
}

void Add(int u, int v, int cap, ll cost)
{
    e[cnt].to = v;
    e[cnt].cap = cap;
    e[cnt].cost = cost;
    e[cnt].nxt = head[u];
    head[u] = cnt ++;

    e[cnt].to = u;
    e[cnt].cap = 0;
    e[cnt].cost = -cost;
    e[cnt].nxt = head[v];
    head[v] = cnt ++;
}

void Build_graph()
{
    Add(src, 1, k, 0);
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= i; j++)
        {
            Add((i - 1) * n + j, n * n + (i - 1) * n + j, 1, a[i][j]);
            Add((i - 1) * n + j, n * n + (i - 1) * n + j, INF, 0);
            if(j < n)
                Add(n * n + (i - 1) * n + j, (i - 1) * n + j + 1, INF, 0);
            if(i < n)
                Add(n * n + (i - 1) * n + j, i * n + j, INF, 0);
        }
    }
    Add(2 * n * n, sk, k, 0);
}

bool SPFA()
{
    memset(vis, false, sizeof(vis));
    memset(dis, -1, sizeof(dis));
    memset(pre, -1, sizeof(pre));
    queue  q;
    q.push(src);
    vis[src] = true;
    dis[src] = 0;
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = false;
        for(int i = head[u]; i != -1; i = e[i].nxt)
        {
            int v = e[i].to;
            int cap = e[i].cap;
            ll cost = e[i].cost;
            if(cap > 0 && dis[v] < dis[u] + cost)
            {
                dis[v] = dis[u] + cost;
                pre[v] = i;
                if(!vis[v])
                {
                    vis[v] = true;
                    q.push(v);
                }
            }
        }
    }
    return dis[sk] != -1;
}

void Augment()
{
    int mi = INF;
    while(SPFA())
    {
        for(int i = sk; i != src; i = e[pre[i] ^ 1].to)
            mi = min(mi, e[pre[i]].cap);
        for(int i = sk; i != src; i = e[pre[i] ^ 1].to)
        {
            ans += (ll)mi * e[pre[i]].cost;
            e[pre[i]].cap -= mi;
            e[pre[i] ^ 1].cap += mi; 
        }
    }
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d %d", &n, &k);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= i; j++)
                scanf("%I64d", &a[i][j]);
        Init(); 
        Build_graph();
        Augment();
        printf("%I64d\n", ans);
    }
}



文科生or理科生

                                                                                时间限制(普通/Java): 1000MS/3000MS         运行内存限制:32768KByte

“Wishare杯”南邮第八届大学生程序设计竞赛之网络预赛 题解报告_第1张图片

题目分析:首先an通过做差得到an = n^2 + 3n + 1 = (n + 2) * (n + 1) - 1,分母提出一个根号n,就是(根号n) * (n + 1)!,分子就是(i + 2)! - (i)!求和,这个高中生都会吧?错位相减,最后再化简可以把分子上的阶乘约掉,至于分母上的,只保留6位小数。。。自己感受去吧
#include 
#include 

int main()
{
    int T;
    scanf("%d", &T);
    while(T --)
    {
        double n;
        scanf("%lf", &n);
        if(n >= 20)
            printf("%.6f\n", (n + 3.0) / sqrt(n));
        else
        {
            double f = 1.0;
            for(int i = 2; i <= n + 1; i++)
                f = f * i * 1.0;
            printf("%.6f\n",  (n + 3.0 - 3.0 / f) / sqrt(n));
        }
    }
}


你可能感兴趣的:(ACM,各类比赛)