今天的题我说实话好像模拟都可以过好多,可是我……自闭了……下午的时候,信竞的老师转换成专业人生导师,自动鸡汤灌溉(什么要保持良好健康乐观积极向上的心态呀,跟吴老师上次说的不要跟别人比要跟自己比真的有异曲同工之妙)(而且还说有些同学没过多少但仍然开开心心的)(感觉说的就是我)。
2642. 游戏 (Standard IO)——博弈sg函数
Time Limits: 2000 ms Memory Limits: 262144 KB
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
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
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
思路
am(mod k) bm(mod k) (a-b)0(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);
}
}