记 2024.4.20

P2953

[USACO09OPEN] Cow Digit Game S

题目描述

Bessie is playing a number game against Farmer John, and she wants you to help her achieve victory.

Game i starts with an integer N_i (1 <= N_i <= 1,000,000). Bessie goes first, and then the two players alternate turns. On each turn, a player can subtract either the largest digit or the smallest non-zero digit from the current number to obtain a new number. For example, from 3014 we may subtract either 1 or 4 to obtain either 3013 or 3010, respectively. The game continues until the number becomes 0, at which point the last player to have taken a turn is the winner.

Bessie and FJ play G (1 <= G <= 100) games. Determine, for each game, whether Bessie or FJ will win, assuming that both play perfectly (that is, on each turn, if the current player has a move that will guarantee his or her win, he or she will take it).

Consider a sample game where N_i = 13. Bessie goes first and takes 3, leaving 10. FJ is forced to take 1, leaving 9. Bessie takes the remainder and wins the game.

贝茜和约翰在玩一个数字游戏.贝茜需要你帮助她.

游戏一共进行了G(1≤G≤100)场.第i场游戏开始于一个正整数Ni(l≤Ni≤1,000,000).游

戏规则是这样的:双方轮流操作,将当前的数字减去一个数,这个数可以是当前数字的最大数码,也可以是最小的非0数码.比如当前的数是3014,操作者可以减去1变成3013,也可以减去4变成3010.若干次操作之后,这个数字会变成0.这时候不能再操作的一方为输家. 贝茜总是先开始操作.如果贝茜和约翰都足够聪明,执行最好的策略.请你计算最后的赢家.

比如,一场游戏开始于13.贝茜将13减去3变成10.约翰只能将10减去1变成9.贝茜再将9减去9变成0.最后贝茜赢.

输入格式

* Line 1: A single integer: G

* Lines 2..G+1: Line i+1 contains the single integer: N_i

输出格式

* Lines 1..G: Line i contains 'YES' if Bessie can win game i, and 'NO' otherwise.

样例 #1

样例输入 #1

2 
9 
10

样例输出 #1

YES 
NO

提示

For the first game, Bessie simply takes the number 9 and wins. For the second game, Bessie must take 1 (since she cannot take 0), and then FJ can win by taking 9.

题意是数只可以减自己每个数位上的非 00 最大值和最小值。

f[i]=(!(f[i-minn]&&f[i-maxn]))minnminn 表示数位上非 00 最小值,maxnmaxn 同理。

注意博弈论推想必胜态必败态状态之间的关系

Code

#include <iostream>
using namespace std;
const int N=1e6+10,INF=0x3f3f3f3f;
bool f[N]={0,1,1,1,1,1,1,1,1,1};
int n;
int main()
{
    int tt;
    cin>>tt;
    for(int i=10;i<=1e6;i++)
    {
        int k=i,minn=INF,maxn=-INF;
        while(k)
        {
            if(k%10!=0) minn=min(minn,k%10);
            if(k%10!=0) maxn=max(maxn,k%10);
            k/=10;
        }
        f[i]=(!(f[i-minn]&&f[i-maxn]));
    }
    while(tt--)
    {
        cin>>n;
        if(f[n]) puts("YES");
        else puts("NO");
    }
    return 0;
}

P2216

[HAOI2007] 理想的正方形

题目描述

有一个 a×ba \times b 的整数组成的矩阵,现请你从中找出一个 n×nn \times n 的正方形区域,使得该区域所有数中的最大值和最小值的差最小。

输入格式

第一行为 33 个整数,分别表示 a,b,na,b,n 的值。

第二行至第 a+1a+1 行每行为 bb 个非负整数,表示矩阵中相应位置上的数。每行相邻两数之间用一空格分隔。

输出格式

仅一个整数,为 a×ba \times b 矩阵中所有“ n×nn \times n 正方形区域中的最大整数和最小整数的差值”的最小值。

样例 #1

样例输入 #1

5 4 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2

样例输出 #1

1

提示

问题规模。

矩阵中的所有数都不超过 1,000,000,0001,000,000,000

20%20\% 的数据 2a,b100,na,nb,n102 \le a,b \le 100,n \le a,n \le b,n \le 10

100%100\% 的数据 2a,b1000,na,nb,n1002 \le a,b \le 1000,n \le a,n \le b,n \le 100

这一看就有单调性啊,考虑二分。

那么 CHECK 怎么写呢?

想到要维护 mid 长的区间最大值,我们想到什么?没错,正是单调队列,或换种说法,滑动窗口。

于是我们维护二维的最大最小单调队列。 做法,此题模板

Code

#include <iostream>
#include <cstring>
#define int long long
using namespace std;
const int N=510;
int a[N][N];
int colmin[N][N],colmax[N][N],rowmin[N][N],rowmax[N][N];
int n,m,k,tt,hh;
int q[N];
bool check(int x)
{
   	memset(colmin,0,sizeof colmin);
   	memset(rowmax,0,sizeof rowmax);
   	memset(rowmin,0,sizeof rowmin);
   	memset(colmax,0,sizeof colmax);
   	int ans=-0x3f3f3f3f;
	for(int i=1;i<=n;i++)
	{
		tt=-1,hh=0;
		for(int j=1;j<=m;j++)
		{
			while(tt>=hh&&q[hh]+x<=j) hh++;
			while(tt>=hh&&a[i][q[tt]]<a[i][j]) tt--;
			q[++tt]=j;
			if(j>=x) colmax[i][j-x+1]=a[i][q[hh]];
		}
	}
	for(int i=1;i<=n;i++)
	{
		tt=-1,hh=0;
		for(int j=1;j<=m;j++)
		{
			while(tt>=hh&&q[hh]+x<=j) hh++;
			while(tt>=hh&&a[i][q[tt]]>a[i][j]) tt--;
			q[++tt]=j;
			if(j>=x) colmin[i][j-x+1]=a[i][q[hh]];
		}
	}
	for(int i=1;i<=m-x+1;i++)
	{
		tt=-1,hh=0;
		for(int j=1;j<=n;j++)
		{
			while(tt>=hh&&q[hh]+x<=j) hh++;
			while(tt>=hh&&colmax[q[tt]][i]<colmax[j][i]) tt--;
			q[++tt]=j;
			if(j>=x) rowmax[j-x+1][i]=colmax[q[hh]][i];
		}
	}
	for(int i=1;i<=m-x+1;i++)
	{
		tt=-1,hh=0;
		for(int j=1;j<=n;j++)
		{
			while(tt>=hh&&q[hh]+x<=j) hh++;
			while(tt>=hh&&colmin[q[tt]][i]>colmin[j][i]) tt--;
			q[++tt]=j;
			if(j>=x) rowmin[j-x+1][i]=colmin[q[hh]][i];
		}
	}
	for(int i=1;i<=n-x+1;i++)
		for(int j=1;j<=m-x+1;j++)
			ans=max(ans,rowmax[i][j]-rowmin[i][j]);
	//cout<<x<<' '<<ans<<' '<<k<<endl;
	return (ans>=k);
}
signed main()
{
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>a[i][j];
    int l=2,r=min(n,m);
    while(l<r)
    {
        int mid=l+r>>1;
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    if(!check(r)) {puts("-1");return 0;}
    cout<<r<<endl;
    return 0;
}
posted @ 2024-04-21 18:08  PM_pro  阅读(23)  评论(0)    收藏  举报  来源