Codeforces Round #706 实录

【A】

就是把一段当成a_(k+1)删掉,剩下的构成回文串,其中一半长度>=k

另外删掉的长度不能为0,还有k=0的恶心情况,以及没及时跳出多输出的case。

又慌又乱,搞我心态,下一题。

【B】

S中的b会增加,当且仅当a=b+1(若a>b,a只能是b+1)

而一旦这种情况出现,以后的操作都是不断地加入最大值+1

那么下界如何变化呢?

对于S,假如里面没有0,b>0,那么似乎我们永远不会加入0到S中

没错。

那么每次加入的永远都会ceil((0+b)/2)。

启发我们思考初始a对后续加入数字的决定作用。

如果初始情况,分为两种a>b,a<b (a=b是不可能的)

如果a<b,那么ceil((a+b)/2)永远不会等于a,也<b,因此加入数字永远不变

如果a>b,即一开始讨论的情况。

就是简单的分类讨论,分析一下。

【C】

黄金矿工背景。n个矿工,y轴上。

没有原点钻石,n个钻石,x轴上。要求一一配对,最小化i距离和。

配对问题,总让我不得不想起什么逆序和乱序和的理论或者说贪心策略。

这里是两条线段,交叉的图像,让我想试试调整法。

最优方案的必要条件,包括不能被调整成功。这等价于

sqrt(x1^2+y1^2)
+
sqrt(x2^2+y2^2)
<=
sqrt(x1^2+y2^2)
+
sqrt(x2^2+y1^2)

根号总是扮演魔鬼的角色。

先溜了,看D题。

公式平方后整理得到

x1y2+x2y1<=x1y1+x2y2

而根据逆序乱序的知识。。(艹)

假设x1<x2,那么应该有y1>y2

于是这样匹配即可。

必要条件变为充分的构造条件。again。

查了一下,排序不等式不要求整数,OK。

但感觉这样算出来结果有点奇怪,还是根据对称性都取成绝对值吧。

哦不,

x1y2+x2y1<=x1y1+x2y2

每个数字都要平方。

但是,「必要条件变为充分的构造条件。again。」这是错的吧。

对于两个mienr和两个mine,它们或者普通配对或者交叉培养,可以这样处理。

但是如果一个mine在另一方案内压根不和这两个mienr的任一个匹配呢?

先不管之前的解法错在哪里。

从图像上,结合三角形的边不等式,不能出现交叉线段。

cin和printf混用,艹。

【D】

国人题啊。。

y!=x

博弈论?至少题面风格是这样的。

每次每人左移或者右移一个位置,但不能挤掉对方的位置,

且新的数字,对Q来说要递减,对D来说要递增。

看E题。

线性结构。

先考虑固定的初始x,y的最优方案。

这几把从哪儿开始入手啊。

p<=n,有意思。哦,p是全排列。

与相连的连续单调块有关。

Q一定不能选最大的p当x

也不能选两边都>它的p当x

Q和D不会互相穿梭。

如果Q走到D走过的位置,然后D这一轮成功应付了后,下一轮Q一定不能走。

对D来说,vice versa。

对于 > > 来说,Q不能选,否则D选它右边,Q第一回就挂

< < 同理,

> < 也不行。

x只能取< >

然后之后就是单向下降的过程。

假设x取了一个顶峰,其两坡(不包含峰)一个长为w1,另一个为w2

设w1>w2,那么y不能取w2上的点,否则会让x必胜。

如果w1是奇数,那么x必败,只要让y取谷底即可。

否则,x必胜。

似乎不管x或者y必然都取在长度最长的坡上(不一定只有一个)

如果这个长度是偶数(算上谷底和峰),那么x必败,否则必胜。

卧槽,似乎只有两边都是奇数才可以。

别忘了边界的时候也结算一遍对应的坡的长度,而不是只有转折的时候结算。

最后15s改完。

艹,还是WA。

卧槽,怎么交错题了,交给E了。

END. 实时rank两千多,爆炸啊。

【E】

在原图基础上挖空使得整体连通,且无环。求任意方案(不要求最小)

感觉是个找点结论利用的构造题(应该不是生成树这样的算法题吧)

想先做E,但是又被顺序吓到。

感觉是经典问题。

star图?

坐标系?象限?

或者一条竖边,其余横边?

两条横边不能连在一起。

标记点的行号不相邻的话,可以直接连横边。

否则,必然,间隔的跳行。

每行可以全取啊。

Go!

Wait,这样依然会可能成环。

Retreat。

要不要讨论别的东西,比如坐标和%4之类的。

 

【F】

没时间看了

【赛后订正】

【D】

首先,我们应该排除一种显然的情况,即最长坡的个数>2的情况,这种情况,y总是可以取一个x永远也无法走到的最长坡上,而x先走,先走完,先败。

如果最长坡只有一个,也不行,因为如果长度为偶数,y只要在这个谷底向上走,x不管是否迎面而走,都是输。如果长度为奇数,那么y只要取这个谷底上面一格,x不管是否迎面而走,都是输。

因此最长坡的数量只能等于2,并且共有一个顶峰(否则就可以按照最长坡个数>2的策略,让y走另一个x走不到的最长坡上开始走,x比败)(如果是共有一个谷底的话,x显然也输)

这种情况,只有坡长为奇数,x才可能赢。且只有这一个位置能赢。

我TM没有对最长坡的个数进行讨论,就差临门一脚啊

#include <bits/stdc++.h>
using namespace std;
#define FOR(i,n) for (int i=1;i<=n;i++)
#define REP(i,a,b) for (int i=a;i<=b;i++)
 
#define pb push_back
#define fi first
#define se second
#define pi pair<int,int>
#define mp make_pair
 
typedef long long ll;
typedef complex<double> comp;
 
const int inf=0x3f3f3f3f;
const ll linf=1e18;
const int N=5e5+10;
const double eps=1e-10;
const ll mo=1e9+7;
 
 
int n;
int a[N];
int l;
int len1,len2;
int L[N],R[N];
int cnt,cnt2;
int main() {
 
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
 
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    cin>>n;
    FOR(i,n) cin>>a[i];
    FOR(i,n) {
        if (i==1||a[i]>a[i-1]) {
            l++;
        } else {
            L[i-1]=l;
            l=1;
        }
        len1=max(len1,l);
    }
    L[n]=l;
    l=0;
    for (int i=n;i>=1;i--) {
        if (i==n||a[i]>a[i+1]) {
            l++;
        } else {
            R[i+1]=l;
            l=1;
        }
        len2=max(len2,l);
    }
    R[1]=l;
    int ans=max(len1,len2);
    if (ans%2) {
        FOR(i,n) if (L[i]==ans) cnt2++;
		FOR(i,n) if (R[i]==ans) cnt2++;
        FOR(i,n) {
            if (L[i]&&R[i]) {
                if (L[i]==ans&&R[i]==ans&&a[i]>a[i-1]&&a[i]>a[i+1]) {
                    cnt++;
                }
            }
        }
        if (cnt!=1||cnt2!=2) cout<<0<<endl;
        else cout<<1<<endl;
    } else cout<<0<<endl;
    return 0;
}

  

【E】

的确是我之前的思路,把某些竖列都取遍,然后生长出横边来连接标记点。

之前没沿着这个思路深入干下去,是因为我发现两个横边会黏在一起构成环,即使间隔一行也可以因为间隔行中的两个标记点造成环,但是,如果间隔2行呢?

这就是正解。题面中的标记点互不相邻(甚至没有公共点,而不仅仅没有公共边!这一点是关键,赛场上我没读出这个意思)就导致了间隔2行不存在实现连通的两个相邻的标记点。

这样,每三列地分组,每一组中间列都取遍,那么这组的标记点必然成为连通块的子集。

接下来就是考虑组与组之间的连接。

我们只要,比如在组A 组B中,组A的第三列的第一个有标记点的位置和组B的第一列的第一个位置都取遍(或者反过来),就一定连通,也不会构成环(当然得先检验是否已经连通了,这种情况我们就什么也不做)

然后把这个做法,从3的倍数扩展到3k+1和3k+2上就行了 。

如果是3k+1,多出的一列,如果还没与前面的连通的话,把最上边第一个有点的位置和前面一组的对应位置给连通。

额,这不行,因为多出的一列,这组本身不一定连通,所以应该是某一行如果有连接的两个位置中有一个1,就对应两个位置都写上1.

如果是3k+2,似乎当成3k+3做也没区别。

#include <bits/stdc++.h>
using namespace std;
#define FOR(i,n) for (int i=1;i<=n;i++)
#define REP(i,a,b) for (int i=a;i<=b;i++)
 
#define pb push_back
#define fi first
#define se second
#define pi pair<int,int>
#define mp make_pair
 
typedef long long ll;
typedef complex<double> comp;
 
const int inf=0x3f3f3f3f;
const ll linf=1e18;
const int N=5e5+10;
const double eps=1e-10;
const ll mo=1e9+7;

int t;
int n,m;
int a[600][600];
int main() {
 
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
 
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    cin>>t;
    while (t--) {
        cin>>n>>m;
        FOR(i,n) FOR(j,m) {
            char c='\n';
            while (c=='\n') cin>>c;
            if (c=='X') a[i][j]=1;
            else a[i][j]=0;
        }
        for (int j=2;j<=m;j+=3) {
            FOR(i,n) a[i][j]=1;
            if (j!=2) {
                bool ok=0;
                FOR(i,n) {
                    if (a[i][j-1]||a[i][j-2]) {
                        a[i][j-1]=a[i][j-2]=1;
                        ok=1;
                        break;
                    }
                }
                if (!ok) a[1][j-1]=a[1][j-2]=1;
            }
        }
        if (m%3==1) {
        	int j=m;
            FOR(i,n) {
                if (a[i][j]) {
                    a[i][j]=a[i][j-1]=1;
                }
            }
		}
		if (m==1) {
			FOR(i,n) a[i][1]=1; 
		}
        FOR(i,n) {
            FOR(j,m) if (a[i][j]) cout<<'X';
            else cout<<'.';
            cout<<endl;
        }
    }
    return 0;
}

  

posted @ 2021-03-10 22:07  AngelKnows  阅读(154)  评论(0)    收藏  举报