【LGR-070】洛谷 3 月月赛 I & EE Round 1 Div.2

【LGR-070】洛谷 3 月月赛 I & EE Round 1 Div.2

A 苏联人 入门

题目描述

你在打EE Round 1, 发现第一题非常无聊, 于是你不打了, 去下国际象棋了。
结果你发现, 由于某种神秘力量的影响, 你的棋子只剩下若干黑色的战车, 若干黑色的主教, 和一只白色的国王了。
由于你很无聊, 所以你把一些棋子放在了 8 × 8 8 \times 8 8×8的棋盘上。
由于你很无聊, 所以你想知道, 国王放在哪些格子上是安全的。 换句话说, 有哪些各自不会被战车和主教攻击到。 当然国王不能放在已经有棋子的地方
为了防止你无聊透顶而不知道国际象棋的规则, 这里给出以下提示(如果你知道规则可以跳过)
国际象棋中, 战车可以横向、竖向移动, 且格数不受限制。但不能越过其他棋子
【LGR-070】洛谷 3 月月赛 I & EE Round 1 Div.2_第1张图片
如图, 黄色的格子为战车能走到(攻击到的)格子。
国际象棋中, 主教可以斜向移动, 且格数不受限制, 但不能越过其他棋子
【LGR-070】洛谷 3 月月赛 I & EE Round 1 Div.2_第2张图片

如图, 黄色的各自为主教能走到(攻击到)的格子。
简单来说, 如果当前位置到目标位置的直线上存在其他棋子, 则可以称为”越过了其他棋子“。
如果目标位置是对方的棋子, 那么移动到目标位置后, 对方的棋子会被吃掉
更进一步的, 你要找的所有位置, 必须满足没有黑色棋子能一步走到。

题目分析

1.有棋子

不能

2.主教

四条直线分别是x-k, y-k;x-k, y+k;x+k, y-k;x+k, y+k;
如果途中途碰到棋子, 那么这条线就失效了, break;

3.战车;

四条线分别是:x, y-k; x, y+k, x+k, y; x-k, y;
棋子处理一样;

代码

for(int i = 1; i <= 8; i++)
{
	for(int j = 1; j <= 8; j++)
	{
		cin >> a[i][j];
		p[i][j] = true;
		if(a[i][j] == '.')
		{
			continue;
		}
		else
		{
			p[i][j] = false;
		}
	}
}
for(int i = 1; i <= n; i++)
{
	for(int j = 1; j <= n; j++)
	{
		if(a[i][j] == 'B')
		{
			for(int k = 1; i-k && j-k; k++)
			{
				if(a[i-k][j-k] != '.')
				{
					break;	
				}
				p[i-k][j-k] = false;
			}
			for(int k = 1; i-k && j+k <= 8; k++)
			{
				if(a[i-k][j+k] != '.')
				{
					break;
				}
				p[i-k][j+k] = false;
			}
			for(int k = 1; i+k <= 8 && j-k; k++)
			{
				if(a[i+k][j-k] != '.')
				{
					break;
				}
				p[i+k][j-k] = false;
			}
			for(int k = 1; i+k <= 8; j+k <= 8; k++)
			{
				if(a[i+k][j+k] !='.')
				{
					break;
				}
				p[i+k][j+k] = false;
			}
		}
		if(a[i][j] == 'R')
		{
			for(int k = 1; j-k ; k++)
			{
				if(a[i][j-k] != '.')
				{
					break;
				}
				p[i][j-k] = false;
			}
			for(int k = 1; i-k; k++)
			{
				if(a[i-k][j] != '.')
				{
					break;
				}
				p[i][j-k] = false;
			}
			for(int k = 1; i+k <= 8; k++)
			{
				if(a[i+k][j] != '.')
				{
					break;
				}
				p[i+k][j] = false;
			}
			for(int k = 1; j + k <= 8; k++)
			{
				if(a[i][j+k] != '.')
				{
					break;
				}
				p[i][j+k] = false;
			}
		}
	}
}
for(int i = 1; i <= 8; i++)
{
	for(int j = 1; j <= 8; j++)
	{
		if(p[i][j] == true)
		{
			cout << 1;
		}
		else
		{
			cout << 0;
		}
	}
	cout << endl;
}
				

B 迫害 普及

题目描述

有k个人, X要对这k个人进行迫害。
这k个人, 每个人都拥有一个数字, 分别从1至k。
X拥有n+m个数字, 这些数字为n个1, 和m个大小可有X决定的数字(每个数字定好后就不能再更换。
X能对这些人进行迫害, 当且仅当他能用手中若干个数的加和等于呗迫害人的数字, 一次迫害就成功了(不会消耗数字)。
由于X权力极大, 又十分邪恶, 他想要从第1个人开始一个一个进行迫害行动。
由于小Z也在这个被迫害的行列里, 他十分的慌张, 希望你来告诉他X能最多能从第一个人开始连续迫害多少个人。
由于被迫害的人太多了, 他十分的慌张, 希望你来告诉他最多能从第一个人开始连续迫害多少个人。
由于被迫害的人太多了, 所以请将答案对1000000007取模;

题目分析

首先, 现在有N个1, 就可以连续迫害N个人,编号从1~N;
现在后面自己选择的数字有两种选择, 第1种:在1~N范围内。第2种, 大于N;
首先明白, 每个选择的数和N个1组合共可以形成N+1个不同的数 (也可以只选自己而不选1)
因为要迫害最多的人, 而且现在1~N已经被迫害了, 所以形成的这N+1个数尽量在N之外去迫害新的人。
又发现, 当选的数大于N的时候。它与N个1组合形成的N+1个数全都能迫害一个新的编号的人。所以第2种数字选择比第1种更优。
又因为必须是连续迫害, 所以我们第一个选择的数必须是N+1, 设这个数能迫害 m 1 m_1 m1个人(后面以此类推:如 m 2 m_2 m2表示第二个数能迫害的人数),这样的话, m 1 m_1 m1 ~ m 1 + n m_1 + n m1+n就都能被迫害了, 所以 m 1 m_1 m1能迫害N+1个人, 所以我们就得到了 m 1 m_1 m1=N+1;
同样, m 2 m_2 m2能迫害 m 1 + N + 1 m_1+N+1 m1+N+1个人( m 2 m_2 m2分别与1~ m 1 + N m_1+N m1+N相结合, 共能形成 m 1 + N + 1 m_1+N+1 m1+N+1个数)
m 3 m_3 m3 = m 2 + m 1 + N + 1 m_2 + m_1 + N + 1 m2+m1+N+1
m 4 m_4 m4 = m 3 + m 2 + m 1 + N + 1 m _3 + m_2 + m_1 + N + 1 m3+m2+m1+N+1
整理代入得:
m 1 = N + 1 m_1 = N+1 m1=N+1;
m 2 = ( N + 1 ) × 2 m_2 = (N+1) \times 2 m2=(N+1)×2;
m 3 = ( N + 1 ) × 4 m_3 = (N+1) \times 4 m3=(N+1)×4
找规律得;
m x = ( N + 1 ) × 2 x − 1 m_x = (N+1) \times 2^{x-1} mx=(N+1)×2x1
考虑答案, 为N张1迫害的人数加上每张牌迫害的人数。
由此得;
A n s = ∑ i = 1 M m i + N Ans = \sum_{i=1}^{M} m_i + N Ans=i=1Mmi+N
整理得 A n s = ( n − 1 ) × ( 2 M − 1 ) + N Ans = (n-1) \times (2^M-1) + N Ans=(n1)×(2M1)+N
快速幂即可;

代码

int qpow(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b&1)  ans=(ans*a)%p;
        a=(a*a)%p;
        b>>=1;
    }
    return ans%p;
}
int main()
{
	cin >> n >> m;
	int Ans = (((n+1) * (qpow(2, m) - 1)) % p + N)%p;
	cout << Ans << endl;
	return 0;
}

C 代价 提高

题目描述

给定一个长度为n+2的序列 a 2 a_2 a2,其中第1个数和第n+2个数固定为1。你每次可以选择序列中间的一个数删除, (不能是第一个和最后一个), 删除位置p上的数的代价为 a p − 1 × a p × a p + 1 a_{p-1} \times a_p \times a_{p+1} ap1×ap×ap+1.你需要执行这个操作直到无法执行为止, 求最小的代价和。

题目思路

考虑这个序列的两种取数代价方式, 一是从两边取, 那么每个数对答案的贡献是 a i × a i − 1 + a i × a i + 1 a_i \times a_{i-1} + a_i \times a_{i+1} ai×ai1+ai×ai+1
二是从中间取, 那么每个数对答案的贡献就是 a i − 1 × a i × a i + 1 a_{i-1} \times a_i \times a_{i+1} ai1×ai×ai+1
两者同时除以 a i a_i ai得: a i − 1 + a i + 1 a_{i-1} + a_{i+1} ai1+ai+1
a i − 1 × a i + 1 a_{i-1} \times a_{i+1} ai1×ai+1
显然当这两个数 > 1 \gt 1 >1时, 第一种方案比第二种要好。
那么我们就把数列分成一段一段的, (以数列中的1为边界)
则每段的答案就是 ∑ a i × a i + 1 + m i n   a i \sum a_i \times a_{i+1} + min\ a_i ai×ai+1+min ai
最后加上1的个数即可。

代码

const int N = 1e5+10;
int n, a[N];
long long ans = 0;
int main()
{
	cin >> n;
	for(int i = 1; i <= n; i++)
	{
		cin >> a[i];
	}
	for(int i = 1, j = 1;i <= n; i = j, j = i+1)
	{
		while(j <= n && a[j] != 1)
		{
			j++;
		}
		ans++;
		if(i+1 != j)
		{
			ans += *min_element(a + i + 1, a + j);
		}
		for(int k = i+1; k <= j-1; k++)
		{
			ans += a[k] * a[k+1];
		}
	}
	printf("%d\n",ans);
}

礼物 省选

题目描述

小Z送了你一个数列, 具体的, 有 a 1 a_1 a1 = 1, a 2 a_2 a2 = 2, a i = 2 a i − 1 + k a i − 2 ( 3 ≤ i ≤ n ) a_i = 2a_{i-1} + ka_{i-2}(3 \leq i \leq n) ai=2ai1+kai2(3in), 其中n是数列的长度, k是她设定的一个正整数参数。
小Z告诉你一个秘密, 这个数列是她精心挑选的, 有着一种奇妙的性质“Primesmooth”———即对于n以内的任何一个质数 p,满足 p ∣ a p p | a_p pap(|是整除记号)。
你很好奇是不是真的有这回事, 于是你写了一个质数发生器, 进行了长达三天三夜的调试, 终于发现了几个反例:有m个质数竟然不满足小Z所说的性质!
由于你已经随机了很久, 你相信别的质数一定满足性质。
为了表明你和小Z心有灵犀, 你现在猜想小Z当时设定的整数k,由于答案很大, 你只需要求出最小的k对一个质数c取模即可。

题目解析

【LGR-070】洛谷 3 月月赛 I & EE Round 1 Div.2_第3张图片
真相了~~

代码

int n,m,q,a[233],mod,ans=1;

struct bitst {
    uint64_t buf[301000000/64/2+1];
    bool operator[](const int&x)
    { return buf[x>>6]>>(x&63)&1; }
    void set(const int&x)
    { buf[x>>6]|=1ull<<(x&63); }
}v;

void solve()
{
    scanf("%d%d%d",&n,&q,&mod);
    for(int i=0; i<q; i++){
        scanf("%d",a+i),--a[i];
        if(!a[i])return puts("-1")*0;
    }
    sort(a,a+q);
    q=unique(a,a+q)-a;
    v.set(0);
    for(int i=9; i<=n; i+=6)
        v.set(i>>1);
    m=n>>1;
    for(int i=2,j=3; (2*i+1)*(2*i+1)<=n; i+=3,j+=3)
    {
        if(!v[i])
        {
            for(int k=6*i+3,x=i*(i+1)*2,y=x+i*2+1; x<=m; x+=k,y+=k)
                v.set(x),v.set(y);
        }
        if(!v[j])
        {
            for(int k=6*j+3,x=j*(j+1)*2,y=x+j*4+2; x<=m; x+=k,y+=k)
                v.set(x),v.set(y);
        }
    }
    int L=n/2/64,now=0,j=0;
    for(int i=0; i<L; i++)
    for(uint64_t s=~v.buf[i]; s; s&=s-1)
    {
        int p=(__builtin_ctzll(s)+(i<<6))<<1|1;
        for(++now; j<q&&a[j]<now; ++j);
        if(a[j]!=now)ans=1ll*ans*p%mod;
    }
    for(uint64_t s=~v.buf[L]; s; s&=s-1)
    {
        int p=(__builtin_ctzll(s)+(L<<6))<<1|1;
        if(p>n)break;
        for(++now; j<q&&a[j]<now; ++j);
        if(a[j]!=now)ans=1ll*ans*p%mod;
    }
    printf("%d",ans-1);
}

你可能感兴趣的:(比赛)