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

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

A 蘇聯人 入門

題目描述

你在打EE Round 1, 發現第一題非常無聊, 於是你不打了, 去下國際象棋了。
結果你發現, 由於某種神祕力量的影響, 你的棋子只剩下若干黑色的戰車, 若干黑色的主教, 和一隻白色的國王了。
由於你很無聊, 所以你把一些棋子放在了8×88 \times 8的棋盤上。
由於你很無聊, 所以你想知道, 國王放在哪些格子上是安全的。 換句話說, 有哪些各自不會被戰車和主教攻擊到。 當然國王不能放在已經有棋子的地方
爲了防止你無聊透頂而不知道國際象棋的規則, 這裏給出以下提示(如果你知道規則可以跳過)
國際象棋中, 戰車可以橫向、豎向移動, 且格數不受限制。但不能越過其他棋子
哈哈哈哈
如圖, 黃色的格子爲戰車能走到(攻擊到的)格子。
國際象棋中, 主教可以斜向移動, 且格數不受限制, 但不能越過其他棋子
在這裏插入圖片描述

如圖, 黃色的各自爲主教能走到(攻擊到)的格子。
簡單來說, 如果當前位置到目標位置的直線上存在其他棋子, 則可以稱爲”越過了其他棋子“。
如果目標位置是對方的棋子, 那麼移動到目標位置後, 對方的棋子會被喫掉
更進一步的, 你要找的所有位置, 必須滿足沒有黑色棋子能一步走到。

題目分析

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, 設這個數能迫害m1m_1個人(後面以此類推:如m2m_2表示第二個數能迫害的人數),這樣的話,m1m_1 ~ m1+nm_1 + n就都能被迫害了, 所以m1m_1能迫害N+1個人, 所以我們就得到了m1m_1=N+1;
同樣, m2m_2能迫害m1+N+1m_1+N+1個人(m2m_2分別與1~m1+Nm_1+N相結合, 共能形成m1+N+1m_1+N+1個數)
m3m_3 = m2+m1+N+1m_2 + m_1 + N + 1
m4m_4 = m3+m2+m1+N+1m _3 + m_2 + m_1 + N + 1
整理代入得:
m1=N+1m_1 = N+1;
m2=(N+1)×2m_2 = (N+1) \times 2;
m3=(N+1)×4m_3 = (N+1) \times 4
找規律得;
mx=(N+1)×2x1m_x = (N+1) \times 2^{x-1}
考慮答案, 爲N張1迫害的人數加上每張牌迫害的人數。
由此得;
Ans=i=1Mmi+N Ans = \sum_{i=1}^{M} m_i + N
整理得Ans=(n1)×(2M1)+NAns = (n-1) \times (2^M-1) + 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的序列a2a_2,其中第1個數和第n+2個數固定爲1。你每次可以選擇序列中間的一個數刪除, (不能是第一個和最後一個), 刪除位置p上的數的代價爲ap1×ap×ap+1a_{p-1} \times a_p \times a_{p+1}.你需要執行這個操作直到無法執行爲止, 求最小的代價和。

題目思路

考慮這個序列的兩種取數代價方式, 一是從兩邊取, 那麼每個數對答案的貢獻是ai×ai1+ai×ai+1a_i \times a_{i-1} + a_i \times a_{i+1}
二是從中間取, 那麼每個數對答案的貢獻就是ai1×ai×ai+1a_{i-1} \times a_i \times a_{i+1}
兩者同時除以aia_i得:ai1+ai+1a_{i-1} + a_{i+1}
ai1×ai+1a_{i-1} \times a_{i+1}
顯然當這兩個數>1\gt 1時, 第一種方案比第二種要好。
那麼我們就把數列分成一段一段的, (以數列中的1爲邊界)
則每段的答案就是ai×ai+1+min ai\sum a_i \times a_{i+1} + min\ a_i
最後加上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送了你一個數列, 具體的, 有a1a_1 = 1, a2a_2 = 2, ai=2ai1+kai2(3in)a_i = 2a_{i-1} + ka_{i-2}(3 \leq i \leq n), 其中n是數列的長度, k是她設定的一個正整數參數。
小Z告訴你一個祕密, 這個數列是她精心挑選的, 有着一種奇妙的性質“Primesmooth”———即對於n以內的任何一個質數 p,滿足papp | a_p(|是整除記號)。
你很好奇是不是真的有這回事, 於是你寫了一個質數發生器, 進行了長達三天三夜的調試, 終於發現了幾個反例:有m個質數竟然不滿足小Z所說的性質!
由於你已經隨機了很久, 你相信別的質數一定滿足性質。
爲了表明你和小Z心有靈犀, 你現在猜想小Z當時設定的整數k,由於答案很大, 你只需要求出最小的k對一個質數c取模即可。

題目解析

在這裏插入圖片描述
真相了~~

代碼

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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章