A simple problem I 【组合数学】【湖南工业大学创新实验室2015年新生赛(一)(重开)】

A simple problem I

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 70   Accepted Submission(s) : 33
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

实话告诉你们,ikids最喜欢下棋了,什么棋他都爱下!不过相比于下棋,作为一个ACMer,他更喜欢研究棋,因为好多题目都是涉及各种棋的(ORZ),这不,最近他就迷上了国际象棋里的车,现在让我来跟你讲讲车的在棋盘中的规则吧!

作为仅次于皇后的棋子,它能竖着走,还能横着走(其实和中国象棋里的車是一样的..hahahah),但是当它遇到处于同行同列的车的时候,它就喜欢把它吃了,如下图所示。


R2、R3就冲突了!这可不是ikids希望的!!!那么,问题来了:
给定两个整数n和k,代表n*n的棋盘,和k个车,问你有多少种摆放,使得没有两个車会出现如同R2,R3这种情况!

Input

第一行输入一个T(T<=100000),代表测试数据组数。
对于每一组,输入两个整数n,k;代表n*n的棋盘,k个车;n<=30,k <=n^2

Output

对于每组数据,输出ans,ans为多少种摆放。

数据保证不会超出unsigned long long int。

Sample Input

8
1 1
2 4
3 1
4 1
4 2
4 3
4 4
4 5

Sample Output

1
0
9
16
72
96
24
0


嗯,据说是组合数学,渣渣表示不知道。不过这题我是这样理解的,从 n 行里选择 k 行,表示 k 个车所放的行,然后从 n 列里选择 k 列,表示 k 个车所放的列,就是组合里的C( n ,k )*C( n, k),然后这个意思是每个车是不一样的,就像排列一样所以要乘 k!。


#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long f(int n,int m)
{
    long long s=1;
    for(int i=n;i>n-m;i--)
        s*=i;
    for(int i=1;i<=m;++i)
        s=s/i;
    return s;
}
int main()
{
    int t,n,k;
    long long ans;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        if(k>n)
        {
            printf("0\n");
            continue;
        }
        ans=f(n,k);
        ans=ans*ans;
        for(int i=1;i<=k;++i)
            ans*=i;
        printf("%lld\n",ans);
    }
    return 0;
}



Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 39   Accepted Submission(s) : 23
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

工大第一美男子月神从阿里回来了,ACM的小伙伴们自然是十分的开心!
当然,他们这么开心除了是想月神之外,也是想狠狠宰月神一顿。
月神毕竟是月神,财大气粗,除了请客之外,他还会解答小伙伴们的疑问。

但是,问题一来,就如同排山倒海,让月神应接不暇,所以,他想让你帮帮忙,代他回答这些问题。

对于每个整数q,代表问题,整数p,代表啪啪啪你要输出的是 a = q^p。

Input

多组输入,每组输入两个整数q和p(1<=q<=10,1<=p<=9)

Output

对于每一组数据首先输入一个case #: #代表第几组数据
然后输出一个整数a,代表结果

Sample Input

1 1
2 2
3 3

Sample Output

case 1:1
case 2:4
case 3:27

Author

ikids


嗯,也没什么说的。。


#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int main()
{
    int p,q,cnt=0;
    while(~scanf("%d%d",&q,&p))
    {
        __int64 ans=1;
        for(int i=1;i<=p;++i)
            ans*=q;
        printf("case %d:%I64d\n",++cnt,ans);
    }
    return 0;
}


A simple problem II

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 34   Accepted Submission(s) : 20
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

嘿嘿,恭喜你,看到了本场比赛最简单的题目!
(友情提示,这题你可千万别
for(i = 0;i <= n;i++) if(i%k==0) ans++;
这样做哦,不然绝对会超时的,ikids除了长的帅,有很多女朋友,还从来不骗人呢!)

废(好)话不多说了,且听题意:

给你一个n,和k,你的任务是输出在0~n里一共有多少个数能够被k整除(如果k在0~n范围内,自然也包括它本身),是不是很简单呢!那就快快AC啊。。说不定现在就有人AC了呢!!

Input

输入有多组数据,每一组输入两个整数n和k

其中 1<=n,k<=10^9

Output

输出一个数字ans,代表0~n内有多少个数整除k。

Sample Input

1 1
2 1

Sample Output

2
3

Author

ikids


额,,没什么要说的


#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int main()
{
    int n,k;
    while(~scanf("%d%d",&n,&k))
    {
        int ans=0;
        ans=n/k+1;
        printf("%d\n",ans);
    }
    return 0;
}



令人向往的舞会

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 69   Accepted Submission(s) : 21
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

学校准备组织一场舞会。许多男生女生打算来参加这次舞会,但是他们的舞蹈水平不尽相同,并且要求每一队,搭档两人的水平等级差应小于等于1,在每个人都不重复的情况下,问最多能构成多少对舞伴?

Input

输入包含多组输入

第一行包含一个数字n(1≤n≤100)代表男生的个数,第二行为 a1,a2,...,an (1≤ai≤100),代表第i个男生的舞蹈水平。

同样的,第三行包含一个数字m(1≤?m≤100)代表女生的个数,第二行为 m1,m2,...,mn (1≤mi≤100),代表第i个的女生舞蹈水平。

Output

输出一个数字,代表可能的最大组数。

Sample Input

4
1 4 6 2
5
5 1 5 7 9
4
1 2 3 4
4
10 11 12 13
5
1 1 1 1 1
3
1 2 3

Sample Output

3
0
2

Author

LJF


嗯,这个应该比较好理解吧,看代码就行了


#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int abs(int a,int b)
{
    return a-b>0?a-b:b-a;
}
int main()
{
    int n,m;
    int a[110],b[110];
    while(~scanf("%d",&n))
    {
        for(int i=0;i<n;++i)
            scanf("%d",&a[i]);
        scanf("%d",&m);
        for(int i=0;i<m;++i)
            scanf("%d",&b[i]);
        sort(a,a+n);
        sort(b,b+m);
        int i=0,j=0,ans=0;
        while(i<n&&j<m)
        {
            if(abs(a[i],b[j])<=1)
            {
                ans++;
                i++,j++;
            }
            else
            {
                if(a[i]>b[j])
                    j++;
                else
                    i++;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}



Too young

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 50   Accepted Submission(s) : 20
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

IP地址有如下形式
a.b.c.d
现在给出两串IP地址,第一串的abcd都以十进制整数给出,第二串abcd都以8位二进制数给出。
判断这两个IP地址是否相同。你可以认为给出的所有IP地址都合法

难度:☆

Input

输入一个正整数t,代表测试数据组数,接下来t组数据,如样例给出

Output

相同输出Yes,不相同输出No.细节见样例

Sample Input

2
1.1.1.1
00000001.00000001.00000001.00000001
20.20.20.20
11111111.11111111.11111111.11111111

Sample Output

Yes
No

Author

bitchbitch

Source

light oj


嗯,就是字符串和进制转换


#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int rec[10]={1,2,4,8,16,32,64,128,256,612};
int tran(char s[],int sa,int ea)
{
    int i=ea,j=0;
    int ans=0;
    while(i>=sa)
    {
        ans+=(s[i]-'0')*rec[j];
        j++;i--;
    }
    return ans;
}
int main()
{
    int t,a,b,c,d,aa,bb,cc,dd;
    char s[40];
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d.%d.%d.%d",&a,&b,&c,&d);
        scanf("%s",s);
        int len=strlen(s);
        int j=0;
        aa=tran(s,0,7);
        //printf("aa=%d ",aa);
        int flag=0;
        if(aa==a)
        {
            bb=tran(s,9,16);
           // printf("bb=%d ",bb);
            if(bb==b)
            {
                cc=tran(s,18,25);
                //printf("cc=%d ",cc);
                if(cc==c)
                {
                    dd=tran(s,27,34);
                    //printf("dd=%d ",dd);
                    if(dd==d)
                        flag=1;
                }
            }
        }
        if(flag)
            printf("Yes\n");
        else
            printf("No\n");
    }
    return 0;
}


Too simple

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 33   Accepted Submission(s) : 17
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

Alice和Bob又在玩游戏惹。有一堆石子,石子总数为n。她们轮流取石子,每个人每次可以取走两个或者一个石子。另外如果Alice先手,那么取走最后一颗石子的输。如果Bob先手,那么取走最后一颗石子的获胜。假设两人都采取最佳策略,你的任务是根据石子数目和谁先手判断谁会赢。

难度:★
(hint:简单找规律即可。如果当前状态能够推出一个先手必败状态,那么当前状态为先手必胜状态。如果当前状态不能推出任一个先手必败状态,那么当前状态为先手必败状态)

Input

输入一个正整数t,接下来t组数据,每组包含n(1<=n<2^31)和Alice或Bob,代表先手的是谁

Output

对每组数据输出一行,输出胜者

Sample Input

3
1 Alice
2 Alice
3 Bob

Sample Output

Bob
Alice
Alice

Author

bitchbitch


嗯,简单基础的博弈吧,自己推一下就出来了


#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int main()
{
    int t,n;
    char s[10];
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%s",&n,s);
        if(strcmp(s,"Alice")==0)
        {
            if(n%3==1)
                printf("Bob\n");
            else
                printf("Alice\n");
        }
        else
        {
            if(n%3==0)
                printf("Alice\n");
            else
                printf("Bob\n");
        }
    }
    return 0;
}


Sometime naive

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 59   Accepted Submission(s) : 2
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

定义回文数:A number is called palindromic when its digits are same from both sides
如1223221, 121, 232 是回文数,而122, 211, 332不是。任意给出一个非常大的数字n,你的任务是找出一个回文数x刚好大于n,即满足以下两个条件:
Ⅰ.这个回文数x大于n
Ⅱ.不存在任何一个回文数,大于n并且小于x

难度:★★

Input

先输入一个整数t,接下来是t组数据
每组数据输入一个整数n,n可能是一个100000位的数字,请用字符读入它

Output

输出满足条件的x,每组数据输出一行

Sample Input

4
1740
9488
2455171
1527614

Sample Output

1771
9559
2455542
1528251

Author

bitchbitch

Source

light oj



嗯,这道题在DIY开放时由于偷懒没来得及修改,考虑多种情况,现在代码也不知道正确与否。。(感觉很不爽啊,代码改出来了,但不知道正确不)


#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 10000010
char s[maxn];
int f(char s[])//判断是否为回文数
{
    int len=strlen(s);
    int i=0,j=len-1;
    if(len&1)
    {
        while(i!=j)
        {
            if(s[i]==s[j])
            {
                i++;j--;
            }
            else
                return 0;
        }
        return 1;
    }
    else
    {
        while(i-j!=1)
        {
            if(s[i]==s[j])
            {
                i++;j--;
            }
            else
                return 0;
        }
        return 1;
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",s);
        int len=strlen(s);
        if(f(s))//本身就是回文数
        {
            int i;
            if(len&1)
                i=len/2;
            else
                i=len/2-1;
            while(s[i]=='9'&&i>=0)
                i--;
            if(i<0)//全由9组成
            {
                s[0]=s[len]='1';
                for(int i=1;i<len;++i)
                    s[i]='0';
                s[len+1]='\0';
                printf("%s\n",s);
            }
            else
            {
                s[i]+=1;
                for(i=i+1;i<=len/2;++i)
                    s[i]='0';
                if(len&1)
                {
                    for(int i=0;i<=len/2;++i)
                        printf("%c",s[i]);
                }
                else
                {
                    for(int i=0;i<len/2;++i)
                        printf("%c",s[i]);
                }
                for(int i=len/2-1;i>=0;i--)
                    printf("%c",s[i]);
                printf("\n");
            }
            continue;
        }
        if(len&1)//长度为奇数
        {
            int tem=len/2;
            int k=1;
            while(s[tem-k]==s[tem+k])//判断从哪个位置开始不符合回文数条件的
                k++;
            if(s[tem-k]<s[tem+k])//左边的小于右边的,若不是这样的,直接将左边的复制给右边
            {
                int i=k;
                while(s[tem-k+i]=='9'&&i>0)
                    i--;
                if(i==0)//表示从中心开始一直到不相同的那个位置之间全为9
                {
                    s[tem-k]+=1;
                    for(int j=tem-k+1;j<=tem;++j)
                        s[j]='0';
                }
                else
                    s[tem-k+i]+=1;
            }
            for(int i=0;i<=tem;++i)
                printf("%c",s[i]);
            for(int i=tem-1;i>=0;i--)
                printf("%c",s[i]);
            printf("\n");
        }
        else
        {//偶数长度时
            int tem=len/2;
            int k=1;
            while(s[tem-k]==s[tem+k-1])
                k++;
            if(s[tem-k]<s[tem+k-1])
            {
                int i=k-1;
                while(s[tem-k+i]=='9'&&i>0)
                    i--;
                if(i==0)
                {
                    s[tem-k]+=1;
                    for(int j=tem-k+1;j<tem;++j)
                        s[j]='0';
                }
                else
                    s[tem-k+i]+=1;
            }
            for(int i=0;i<tem;++i)
                printf("%c",s[i]);
            for(int i=tem-1;i>=0;i--)
                printf("%c",s[i]);
            printf("\n");
        }
    }
    return 0;
}





1212

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 43   Accepted Submission(s) : 16
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

双十二快到了, 然而Ikids 学长很不爽, 因为他的基友抛弃了他
所以他看到 “12” 就会很不开心, 然而Ikids学长要处理很多字符
串, 所以你要帮他把 字符串中的 “12” 找出来, 删除掉, 然而
这样会把串分割开来, Ikids学长就头疼了, 字符串的数目变了。
所以你也要数出字符串的个数!

Input

输入包含多组输入

输入一个 N , 表示原来有多少串, (0 <= N < 100)
接下来 N 行, 每行输入 一个长度不超过 1000的字符串

Output

输出 最后剩下的 串的数目

Sample Input

3
32145612558
15649848894
54651233658

Sample Output

5


嗯,简单的字符串,考虑一下全由12组成的字符串和12在字符串开头和结尾的就OK了


#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int main()
{
    int n;
    char s[110][1010];
    while(~scanf("%d",&n))
    {
        int ans=n;
        for(int i=0;i<n;++i)
            scanf("%s",s[i]);
        for(int i=0;i<n;++i)
        {
            int len=strlen(s[i]);
            int flag1=1,flag2=1;
            for(int j=0;j<len;++j)
            {
                if(len%2==0)
                {
                    if(j&1&&s[i][j]!='2'&&flag1)
                        flag1=0;
                    if(j%2==0&&s[i][j]!='1'&&flag2)
                        flag2=0;
                }
                else
                    flag1=flag2=0;
                if(s[i][j]=='1'&&s[i][j+1]=='2'&&(j!=0)&&(j!=len-2))
                {
                    if(s[i][j+2]!='1'||s[i][j+3]!='2')
                        ans++;
                }
            }
            if(flag1&&flag2)
                ans--;
        }
        printf("%d\n",ans);
    }
    return 0;
}


分数统计

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 38   Accepted Submission(s) : 19
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

双十二的问题处理完了, Ikids 学长又遇到了一个
棘手的问题,现在Ikids学长有许多人员要统计他们
的总分数, 需要你帮忙, Ikids 学长怕问题太过
麻烦, 好心的把人员都编号了。

Input

输入包含多组输入

输入 M , M 表示 M条记录
每条记录包含两个整数,分别代表人的编号和分数
M < 1000
编号,分数 < 1e9 + 7;

Output

将所有被记录的人按照编号从小到大的方式
输出他们的 编号, 分数。

Sample Input

5
2 3
3 2
4 2
2 1
2 1

Sample Output

2 5
3 2
4 2


嗯,简单的结构体应用


#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 1010
struct lnode
{
    __int64 f,v;
};
lnode node[maxn];
int cmp(lnode a,lnode b)
{
    return a.f<b.f;
}
int main()
{
    int m;
    __int64 a,b;
    while(~scanf("%d",&m))
    {
        int i=0;
        while(m--)
        {
            scanf("%I64d%I64d",&a,&b);
            node[i].f=a;
            node[i].v=b;
            i++;
        }
        sort(node,node+i,cmp);
        for(int j=0;j<i;++j)
        {
            __int64 ans=node[j].v;
            while(node[j+1].f==node[j].f)
            {
                ans+=node[j+1].v;
                j++;
            }
            printf("%I64d %I64d\n",node[j].f,ans);
        }
    }
    return 0;
}


Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 37   Accepted Submission(s) : 12
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

前几天是双十一,大家或多或少为马大哥的900亿的交易额做了贡献= =但你们萌萌哒的tang学姐没有钱所以并不能在双十一那天抢东西。所以她就只能刷题.

不过她遇到一道题,思考一会后,找到了解题思路,正准备做,却发现大家都买了好多好吃的,她就不想写了,于是让你帮忙。

题目是这样的。给出一个长度为n的整数数列a1,a2,a3....an。然后给出一个整数K,求一个区间[i, j],(1 <= i <= j <= n),使得a[i] + ... + a[j] = K。
如果存在,输出2个数i, j,分别是区间的起始和结束位置。如果存在多个,输出i最小的。如果i相等,输出j最小的,如果没有输出No Solution。大家快来帮帮萌萌哒的tang学姐

Input

多组输入.
第一行输入两个数n和K,n表示数列的长度,K表示要求的和(2 <= N <= 10000,-10^9 <= K <= 10^9)
然后有n行,每一行有一个数,表示数列中的元素。

Output

如果存在区间输出两个整数,代表区间的起始和结束的位置,如果不存在输出No Solution

Sample Input

6 10
1
2
3
4
5
6

Sample Output

1 4
Tip:这题数据较大,最好用64位整数。


嗯,就直接循环出来的


#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 10010
int r[maxn];
int main()
{
    int n,flag;
    __int64 k,ans;
    while(~scanf("%d%I64d",&n,&k))
    {
        flag=0;
        for(int i=0;i<n;++i)
            scanf("%d",&r[i]);
        for(int i=0;i<n;++i)
        {
            ans=0;
            for(int j=i;j<n;++j)
            {
                ans+=r[j];
                if(ans==k)
                {
                    printf("%d %d\n",i+1,j+1);
                    flag=1;
                    break;
                }
            }
            if(flag)
                break;
        }
        if(!flag)
            printf("No Solution\n");
    }



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值