外培D1题解

今天的题我说实话好像模拟都可以过好多,可是我……自闭了……下午的时候,信竞的老师转换成专业人生导师,自动鸡汤灌溉(什么要保持良好健康乐观积极向上的心态呀,跟吴老师上次说的不要跟别人比要跟自己比真的有异曲同工之妙)(而且还说有些同学没过多少但仍然开开心心的)(感觉说的就是我)。

2642. 游戏 (Standard IO)——博弈sg函数

Time Limits: 2000 ms  Memory Limits: 262144 KB

Goto ProblemSet

Description

Alice和Bob在玩一个游戏,游戏是在一个N*N的矩阵上进行的,每个格子上都有

一个正整数。当轮到Alice/Bob时,他/她可以选择最后一列或最后一行,并将其删除,但

必须保证选择的这一行或这一列所有数的和为偶数。如果他/她不能删除最后一行或最后一

列,那么他/她就输了。两人都用最优策略来玩游戏,Alice先手,问Alice是否可以必胜?

Input

第一行:T,表示数据组数

对于每组数据的第一行:N

接下来N行,每行N个数,描述这个矩阵

Output

如果Alice必胜输出W,否则输出L

Sample Input

2
2
2 4
6 8
3
5 4 2
1 5 9
7 3 8

Sample Output

L
W

Data Constraint Hint

100%数据满足
1<=N<=1000
保证每一行或每一列的和不会超过2*10^9
1<=T<=5

思路

f[i][j]=0:在(i,j)时是必败态;则f[i][j]=1:在(i,j)时是必胜态

当第i行可删且f[i-1][j]=0时f[i][j]为必胜态

于列相同当第i列可删且f[i][j-1]=0时f[i][j]为必胜态

用位运算要快得多所以以后要记住0^0=0 0^1=1 1^1=0其实以前就学过感觉自己记性真的不太好(也许是还不够用心吧,突然感伤)。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 1002
int t,n,a;
int li[MAXN],lj[MAXN];
bool f[MAXN][MAXN];
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		//int ans=2*n;
		for(int i=1;i<=n;i++)
			li[i]=lj[i]=0;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
			{
				f[i][j]=0;
				scanf("%d",&a);
				a%=2;
				li[i]=li[i]^a;
				lj[j]=lj[j]^a;
				if(!li[i]&&!f[i-1][j])f[i][j]=1;
				if(!lj[j]&&!f[i][j-1])f[i][j]=1;
			}
		if(f[n][n])printf("W\n");
		else printf("L\n");
	}
}

2643. 六边形 (Standard IO)——暴力模拟(找规律)

Time Limits: 100 ms  Memory Limits: 262144 KB

Goto ProblemSet

Description

棋盘是由许多个六边形构成的,共有5种不同的六边形编号为1到5,棋盘的生成规

则如下:

1.从中心的一个六边形开始,逆时针向外生成一个个六边形。

2.对于刚生成的一个六边形,我们要确定它的种类,它的种类必须满足与已生成的相

邻的六边形不同。

3.如果有多个种类可以选,我们选择出现次数最少的种类。

4.情况3下还有多个种类可以选,我们选择数字编号最小的。

现在要你求第N个生成的六边形的编号?

前14个六边形生成图如下:

 

Input

第一行:T,表示数据组数

接下来T行,每行一个数:N,表示第N个六边形

Output

共t行,每行一个数,表示第N个数据的答案

Sample Input

4 
1 
4 
10 
100 

Sample Output

1 
4 
5 
5 

Data Constraint Hint

100%数据满足
1<=T<=20

1<=N<=10000

思路

模拟可过,还有规律我到时候再补。

模拟的话我以一点去影响其他点,1跟2有点特别就单独处理

1影响的点:2 3 4 5 6 7

2:7 8 9 10

3:10 11 12

4:12 13 14

5:14 15 16

6:16 17 18

7:18 19

8:19 20 21

根据之前影响该点的点数可算出它会影响的点数,影响点nxt是连续的.

代码

#include<cstdio>
#include<vector>
using namespace std;
#define MAXN 10500
vector<int>g[MAXN];
int t,a[MAXN],s[10],n[22],mm;
bool f[6];
int main()
{
	scanf("%d",&t);
	for(int i=1;i<=t;i++)
	{
		scanf("%d",&n[i]);
		mm=max(mm,n[i]);
	}
	s[6]=MAXN;
	int nxt=10;
	a[1]=1;a[2]=2;
	for(int i=2;i<=7;i++)
		g[i].push_back(1);
	for(int i=7;i<=10;i++)
		g[i].push_back(2);
	s[1]++;s[2]++;
	for(int i=3;i<=mm;i++)
	{
		int r=6;
		f[1]=f[2]=f[3]=f[4]=f[5]=0;
		f[a[i-1]]=1;
		int l=g[i].size();
		for(int j=0;j<l;j++)
		{
			f[a[g[i][j]]]=1;
			//printf("%d ",g[i][j]);
		}
		for(int k=1;k<=5;k++)
			if(!f[k])
				if(s[k]<s[r]||(s[k]==s[r]&&k<r))r=k;
		a[i]=r;
	//	printf("\n %d--%d\n",i,r);
		s[r]++;
		for(int k=1;k<5-l;k++,nxt++)
			g[nxt].push_back(i);
		//printf("*%d\n",nxt);
		nxt--;
	}
	for(int i=1;i<=t;i++)
	{
		printf("%d\n",a[n[i]]);
	}
}

2644. 数列 (Standard IO)——同余

Time Limits: 1000 ms  Memory Limits: 262144 KB 

Goto ProblemSet

Description

给你一个长度为N的正整数序列,如果一个连续的子序列,子序列的和能够被K整

除,那么就视此子序列合法,求原序列包括多少个合法的连续子序列?

对于一个长度为8的序列,K=4的情况:2, 1, 2, 1, 1, 2, 1, 2 。它的答案为6,子序列

是位置1->位置8,2->4,2->7,3->5,4->6,5->7。

Input

第一行:T,表示数据组数

对于每组数据:

第一行:2个数,K,N

第二行:N个数,表示这个序列

Output

共T行,每行一个数表示答案

Sample Input

2 
7 3 
1 2 3 
4 8 
2 1 2 1 1 2 1 2 

Sample Output

0 
6 

Data Constraint Hint

100%数据满足
1<=T<=20
1<=N<=50000
1<=K<=1000000
序列的每个数<=1000000000

思路

a\equivm(mod k)  b\equivm(mod k)  (a-b)\equiv0(mod k) 

把模k的余数排序,同余算个数

代码

#include<cstdio>
#include<algorithm>
using namespace std; 
#define MAXN 50002
int t,n,k,a,s[MAXN];
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		s[0]=0;
		long long ans=0;
		scanf("%d%d",&k,&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a);
			s[i]=(s[i-1]+a%k)%k;
		}
		s[n+1]=-1;
		sort(s+1,s+n+1);
		int i;
		long long cnt=0;
		for(i=1;i<=n;i++)
			if(s[i]==0)cnt++;
			else break;
		ans+=cnt+(cnt-1)*cnt/2;
		cnt=0;
		for(;i<=n+1;i++)
			if(s[i]==s[i-1])cnt++;
			else
			{
			//	printf("-%d %d %d\n",i,cnt,ans);
				ans+=(cnt-1)*cnt/2;
				cnt=1;
			}
		printf("%lld\n",ans);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值