链接:​​https://ac.nowcoder.com/acm/contest/18462/F​





Dia and Ruby take turns playing a game using an n x n square chocolate bar. Each turn, the current player must do one of the following (Ruby will go first):



1. Select a prime number p that has not been selected by any player in the previous rounds. Then, choose a p x p square that does not contain any empty squares on the chocolate bar and eat up every chocolate square within the p x p square. 


2. Eat an arbitrary 1 x 1 chocolate square on the bar. 



The player who eats up the last chocolate square wins. Initially, some squares on the chocolate bar are already eaten. If both players play optimally, who will win the game? Note: “optimally” means if any player has a strategy to win no matter how their opponent responds, they will take that move – optimizing their chance of winning. 

输入描述:


Input consists of multiple lines. The first line contains a single integer, n, (1 <= n <= 2000) whichgives the dimensions of the chocolate bar and indicates there are n lines of data that follow thatdescribe the chocolate bar.


 


Each line contains n characters consisting of X (indicating an empty square) or (indicating achocolate square). 


输出描述:

The output line consists of the word RUBY if Ruby is the winner or DIA if Dia is the winner.

  

  如果没有操作1,每次一个一个拿则只需要判断刚开始的巧克力总数的奇偶性。总所周知,质数除了2都是奇数。所以可以用操作1拿质数长度的正方形巧克力后,只有2*2可以维持拿前后的奇偶性扭转战局,因此关于2*2做如下讨论:


如果总数为偶数:
如果当前有2*2的区域:就取一个2*2,先手胜
如果当前没有2*2的区域:双方只能1个1个取,先手输
如果总数为奇数:
先手不能取2*2的区域自掘坟墓。
如果先手能取1*1或2以外的p*p区域后使得场上没有2*2的区域,就取他使得大家只能1个1个取,先手胜
如果先手所有情况下都无法保证取完之后没有2*2区域,后手将取2*2的区域使得先手输

  对于总数为奇数的情况,我刚开始写了个找一个长度大于等于2的坑去填他,wa了。于是想了个dp的方法。预处理出质数数组prime并把prime[1]换成1作为先手可用的正方形长度。dp出以每个点为左上角的最大正方形长度,以每个点为右下角的2*2正方形数量前缀和c[i][j]。这样可以枚举出 以所有点为左上角取最大可取正方形后 减小的2*2正方形数量,与总的2*2正方形数量做比较,如果相同输出先手胜,否则先手输。

  总所周知,a[lower_bound(b+1,b+1+sum,x)-a]是在长为sum的b数组中找大于等于x的第一个数,那么我们可以用a[lower_bound(b+1,b+1+sum,x+1)-a-1]得到小于等于x的第一个数。

ICPC Greater New York Region 2020 F_i++ICPC Greater New York Region 2020 F_#include_02


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
int x;scanf("%d",&x);return x;
}
int n,a[2010][2010],c[2010][2010],maxx[2010][2010],maxy[2010][2010],len[2010][2010];
string s;
int sum;
bool check()
{
for(int i=1;i<n;i++)
for(int j=1;j<n;j++)
if(a[i][j]+a[i][j+1]+a[i+1][j]+a[i+1][j+1]==4)
return 1;
return 0;
}
int minn(int x,int y,int z)
{
return min(min(x,y),z);
}

int tot,prime[3010],v[3010];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>s;
for(int j=0;j<n;j++)
{
if(s[j]=='-')
a[i][j+1]=1,sum++;
else
a[i][j+1]=0;
}
}
if(sum%2==0)
{
if(check())
cout<<"RUBY";
else
cout<<"DIA";
return 0;
}
sum=0;

for(int i=2;i<=3000;i++)
{
if(v[i]==0)
{
tot++;
prime[tot]=i;
}
for(int f=1;f<=tot;f++)
{
if(i*prime[f]>3000)
break;
v[i*prime[f]]=1;
if(i%prime[f]==0)
break;
}
}
prime[1]=1;
sum=0;
for(int i=1;i<=n+1;i++)
for(int j=1;j<=n+1;j++)
{
sum+=(a[i][j]+a[i][j+1]+a[i+1][j]+a[i+1][j+1]==4);
c[i][j]=(c[i-1][j]+c[i][j-1]-c[i-1][j-1]+(a[i][j]+a[i][j-1]+a[i-1][j]+a[i-1][j-1]==4));
}
for(int i=n;i;i--)
{
for(int j=n;j;j--)
{
if(a[i][j]==0)
continue;
maxx[i][j]=maxx[i][j+1]+1;
maxy[i][j]=maxy[i+1][j]+1;
len[i][j]=minn(maxx[i][j],maxy[i][j],len[i+1][j+1]+1);
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
len[i][j]=prime[lower_bound(prime+1,prime+1+tot,len[i][j]+1)-prime-1];
if(len[i][j]==2)
len[i][j]=1;
if(c[i+len[i][j]][j+len[i][j]]-c[i+len[i][j]][j-1]-c[i-1][j+len[i][j]]+c[i-1][j-1]==sum)
{
cout<<"RUBY";
return 0;
}
}
}
cout<<"DIA";
}

View Code