本学期最后一次周赛题解

18 篇文章 0 订阅
15 篇文章 0 订阅

1117: Hkhv喜欢搭积木游戏

时间限制: 1 Sec   内存限制: 128 MB
提交: 33   解决: 4

题目描述

六一儿童节的时候,Hkhv买了n个积木(编号1到n)。他将积木散落在地上,此时他们单个在地上。
现在有m个操作,操作有两种:
1 a b 表示将含有编号为a的积木堆叠到含有编号为b的积木堆上,此时形成了一个新的积木堆。这里保证a积木堆和b积木堆不是同一个堆。
2 a 表示询问输出含有编号a的积木堆中有多少个木块。

输入


有t(t <= 20)组数据,每组数据输入n和m(1 <= n , m <= 50),接下来m行输入操作。

输出

对于每组询问操作,输出其答案。

样例输入

1
2 3
2 1
1 1 2
2 1

样例输出

1
2

简单并查集按秩合并,本来是最先A掉的,换了个OJ交的比较晚……

代码:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define MM(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long LL;
const int N=1010;
int pre[N],ran[N];
int find(int n)
{
    if(n!=pre[n])
        return pre[n]=find(pre[n]);
    return pre[n];
}
void joint(int a,int b)
{
    int fa=find(a),fb=find(b);
    pre[fa]=fb;
    ran[fb]+=ran[fa];
    ran[fa]=0;
}
void init()
{
    for (int i=0; i<N; i++)
    {
        ran[i]=1;
        pre[i]=i;
    }
}
int main(void)
{
    int tcase,i,j,m,q,l,r,n,a,b,ops;
    scanf("%d",&tcase);
    while (tcase--)
    {
        scanf("%d%d",&n,&m);
        init();
        for (i=0; i<m; i++)
        {
            scanf("%d",&ops);
            if(ops==1)
            {
                scanf("%d%d",&a,&b);
                joint(a,b);
            }
            else if(ops==2)
            {
                scanf("%d",&a);
                printf("%d\n",ran[find(a)]);
            }       
        }
    }
    return 0;
}

1118: Hkhv喜欢'越狱'

时间限制: 1 Sec   内存限制: 128 MB
提交: 26   解决: 5

题目描述

Hkhv喜欢看片,尤其是那种美国动作片。最近他看了一部片子叫‘越狱’,总是梦想自己是个犯人,然后越狱...
言归正传,他现在有这样一个思考,假如有一个监狱,监狱里有N个房间(编号为0到N-1),每个房间关押一个犯人。有M种宗教信仰,每个犯人信仰其中一种。如果相邻房间的犯人宗教信仰相同,就可能发生越狱,求有多少种可能情况发生越狱。

输入


有多组输入数据,每组数据输入两个整数M,N (1<=M <=10^8,1<=N <=10^12)

输出

可能越狱的状态数,模100003取余

样例输入

2 3

样例输出

6

提示

6种状态为(000)(001)(011)(100)(110)(111)


本来以为是DP(没错我就是有DP恐惧症),后来发现范围比较大不可能开这么大的数组,应该是什么排列组合的吧。然后看没人A也就放弃了。学长讲了下,感觉确实是经验不足题目本身不难。需要逆向思维:你要求一个排列所有出现相邻重复的情况,正着求比较麻烦考虑的情况很多,但是反着求只需要求出所有的情况减去全部不相邻相同情况即可,前者是M*M*M*········(N个M相乘)=M^N;后者的话第一个房间情况数是M第二个房间不跟第一个一样即可为M-1,第三个房间跟第二个不相同即可也是M-1……以此类推,就是M*(M-1)*(M-1)*······(N个M-1)=M*(M-1)^(N-1),然后做差,最后若是得到的M^N%mod小于M*(M-1)^(N-1)%mod,正向取模即可。

代码:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define MM(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long LL;
const LL mod=100003;
LL qpow(LL a,LL b)
{
    LL r=1,bas=a;
    while (b!=0)
    {
        if(b&1)
            r=r*bas%mod;
        bas=bas*bas%mod;
        b>>=1;
    }
    return r%mod;
}
int main(void)
{
    LL m,n;
    while (cin>>m>>n)
    {
        cout<<((qpow(m,n)-m*qpow(m-1,n-1)%mod)+mod)%mod<<endl;
    }
    return 0;
}

1119: 杨神爱上0

时间限制: 1 Sec   内存限制: 128 MB
提交: 26   解决: 4

题目描述

杨神最近很爱数字0,但是他也只会用阶乘来计算。于是,他想知道,有没有数字阶乘的末尾有n个0,他又把这个题目抛给了各位巨巨。

输入

测试数据有多组 ,输入数字n(n <= 100000)

输出

如果存在多个数字首先输出k,代表有k个数字的阶乘的末尾有n个0
然后接下来一行输出k个数,每个数字之间用空格隔开,最后一个数字末尾没有空格

样例输入

1
5

样例输出

5
5 6 7 8 9
0


想了一会儿,跟那个求N!末尾0个数的题目有点像,一个数要出现0显然需要2与5,然后我也忘记了2好像是肯定比5多的,我反正打了两个表,显然min(cnt_2,cnt_5)==n时ans++,由于末尾零肯定越来越多,左边大于n的时候break。最后数组开到100w,10w太小WA几次……

代码:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define MM(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long LL;
int five[1000011],two[1000011];
int ans[10010];
inline int cal(int n)
{
    int r=0;
    while(n%5==0&&n!=0)
    {
        r++;
        n/=5;
    }
    return r;
}
inline int calt(int n)
{
    int r=0;
    while(n%2==0&&n!=0)
    {
        r++;
        n/=2;
    }   
    return r;
}
int main(void)
{
    int a,b,n,i,j;
    for (i=1; i<1000010; i++)
    {
        five[i]=five[i-1]+cal(i);
    }
    for (i=1; i<1000010; i++)
    {
        two[i]=two[i-1]+calt(i);
    }
    while (~scanf("%d",&n))
    {
        MM(ans);
        int cnt=0;
        for (i=0; i<1000010; i++)
        {
            if((two[i]==n&&five[i]>=two[i])||(five[i]==n&&two[i]>=five[i]))
            {
                ans[cnt++]=i;
            }
            if(min(two[i],five[i])>n)
                break;
        }
        printf("%d\n",cnt);
        for (i=0; i<cnt ;i++)
        {
            printf("%d%s",ans[i],i==cnt-1?"\n":" ");
        }
    }
    return 0;
}


1120: 庆祝

时间限制: 1 Sec   内存限制: 128 MB
提交: 17   解决: 4

题目描述

最近天气终于不是大暴雨了,杨神就对我们说,我们要不开瓶大雪碧来庆祝庆祝吧。然后杨神想模仿电视上的庆功宴一样,杯子叠成n层第i层有i个杯子,然后把雪碧倒在最上面的一个杯子。
这个时候杨神看着缓缓流下的雪碧有了个想法。假如没1s流出来的雪碧恰好能填满一个杯子,那么t秒的时候有多少个杯子被填满了(如果到了最后一层,那么么多余的雪碧就会浪费掉)。希望你们这些大牛能帮杨神解答。

输入

测试数据有多粗,每组有一个n(1<= n <= 10)代表酒杯有n层,然后一个t( 1<=t<=10000)代表t秒

输出

一个整数,代表多少个杯子被填满了

样例输入

3 5
4 8

样例输出

4
6

这题刚开始就想歪了,一直没搞出来,而且越想越觉得麻烦(帅的人早就A了,我丑我还在想……),听学长一讲……原来这么简单。类似于杨辉三角,两个for即可,数组要用double不然分数形式就无法保留了。

代码:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define MM(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long LL;
double dp[15][10010];
int main(void)
{
    int n,i,j,ans;
    double t;
    while (cin>>n>>t)
    {
        for (i=0; i<15; i++)
        {
            for (j=0; j<10010; j++)
            {
                dp[i][j]=0;
            }
        }
        dp[1][1]=t;
        for (i=1; i<=n; i++)
        {
            for (j=1; j<=i; j++)
            {
                if(dp[i][j]>1)
                {
                    double res=dp[i][j]-1;
                    dp[i][j]=1;
                    dp[i+1][j]+=res/2;
                    dp[i+1][j+1]+=res/2;
                }
            }
        }
        int cnt=0;
        for (i=1; i<=n; i++)
        {
            for (j=1; j<=i; j++)
            {
                if(dp[i][j]>=1)
                    cnt++;
            }
        }
        cout<<cnt<<endl;
    }
    return 0;
}

1121: Runes

时间限制: 1 Sec   内存限制: 128 MB
提交: 9   解决: 3

题目描述

You are helping an archaeologist decipher some runes. He knows that this ancient society used a Base 10 system, and that they never start a number with a leading zero. He’s figured out most of the digits as well as a few operators, but he needs your help to figure out the rest.

The professor will give you a simple math expression. He has converted all of the runes he knows into digits. The only operators he knows are addition (+), subtraction (-), and multiplication (*), so those are the only ones that will appear. Each number will be in the range from −999,999 to 999, 999, and will consist of only the digits ‘0’–‘9’, possibly a leading ‘-’, and a few ‘?’s. The ‘?’s represent a digit rune that the professor doesn’t know (never an operator, an ‘=’, or a leading ‘-’). All of the ‘?’s in an expression will represent the same digit (0–9), and it won’t be one of the other given digits in the expression.

Given an expression, figure out the value of the rune represented by the question mark. If more than one digit works, give the lowest one. If no digit works, well, that’s bad news for the professor—it means that he’s got some of his runes wrong. Output −1 in that case. 

输入

The sample data will start with the number of test cases T (1 ≤ T ≤ 100). Each test case will consist of a single line, of the form:

[number][op][number]=[number]

Each [number] will consist of only the digits ‘0’-‘9’, with possibly a single leading minus ‘-’, and possibly some ‘?’s. No number will begin with a leading ‘0’ unless it is 0, no number will begin with -0, and no number will have more than 6 characters (digits or ?s). The [op] will separate the first and second [number]s, and will be one of: +, - or *. The = will always be present between the second and third [number]s. There will be no spaces, tabs, or other characters. There is guaranteed to be at least one ? in every equation. 

输出

Output the lowest digit that will make the equation work when substituted for the ?s, or output −1 if no digit will work. Output no extra spaces or blank lines. 

样例输入

 5
1+1=?
123*45?=5?088
-5?*-1=5?
19--45=5?
??*??=302?

样例输出

2
6
0
-1
5

这题我也是智障了,只判断了前两个数却忘记去判断第三个数字是否存在前导0的情况,在原来的OJ上随便做做的时候刷了一页WA,比赛刚开始的时候还是不知道问题在哪有点方, 还好最后发现了这个问题A掉了。用重定向+string类代码量比较少,有大佬三四百行的代码A的这题。我们3000+B他1W4+B。。果然是大佬,膜拜一下

代码:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define MM(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long LL;
int vis[100];
bool zero(string s)
{
	if(s[0]=='0')
	{
		if(s.size()>=2)
			return true;
	}
	else if(s[0]=='+'||s[0]=='-')
	{
		if(s[1]=='0'&&s.size()>=3)
			return true;
	}
	return false;
}
bool see(string a,string b)
{
	int flag;
	int in;
	for (int i=0; i<a.size(); i++)
	{
		if(a[i]=='*')
		{
			flag=1;
			a[i]=' ';
			in=i;
			break;
		}
		else if(a[i]=='+'&&i!=0)
		{
			flag=2;
			a[i]=' ';
			in=i;
			break;
		}
		else if(a[i]=='-'&&i!=0)
		{
			flag=3;
			a[i]=' ';
			in=i;
			break;
		}
	}
	string ta,tb;
	ta=a.substr(0,in);
	tb=a.substr(in+1,a.size()-1-in);
	if(zero(ta)||zero(tb)||zero(b))
		return false;
	istringstream sin(a);
	istringstream kin(b);
	LL A,B,C;
	sin>>A>>B;
	kin>>C;
	if(flag==1)
	{
		if(A*B==C)
			return true;
	}
	else if(flag==2)
	{
		if(A+B==C)
			return true;
	}
	else if(flag==3)
	{
		if(A-B==C)
			return true;
	}
	return false;
}
int main(void)
{
	int tcase,i,j,index;
	string s,a,b;
	cin>>tcase;
	while (tcase--)
	{
		cin>>s;
		MM(vis);
		int p=0;
		string temp;
		for (i=0; i<s.size(); i++)
		{
			if(s[i]>='0'&&s[i]<='9')
				vis[s[i]-'0']=1;
			if(s[i]=='=')
				index=i;
		}
		for (i=0; i<=9; i++)
		{ 
			if(vis[i])
				continue;
			temp=s;
			for (j=0; j<temp.size(); j++)
				if(temp[j]=='?')
					temp[j]=i+'0';
			a=temp.substr(0,index);
			b=temp.substr(index+1,temp.size()-1+index+1+1);
			if(see(a,b))
			{
				cout<<i<<endl;
				p=1;
				break;
			}
		}
		if(!p)
			cout<<"-1"<<endl;
	}
	return 0;
}


这学期的周赛到此也就结束了,可以好好地玩一下其他东西了比如什么安装总是出错的vs2015(我不信我装不起来打印不出hello world),顺便看视频学点java,这个学期自学了很多东西,并查集、SPFA、迪杰斯特拉、拓扑排序、弗洛伊德、树状数组、克鲁斯卡尔、矩阵快速幂、KMP、RMQ、Manacher以及一些预处理小技巧,收获很多。下个学期更加努力吧

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值