Codeforces Round #630 (Div. 2)

A. Exercising Walk

题目链接

void solve()
{
    int a,b,c,d,a1,b1,a2,b2,na,nb;
    rd(a),rd(b),rd(c),rd(d);
    rd(na),rd(nb),rd(a1),rd(b1),rd(a2),rd(b2);
    if(a1>a2) swap(a1,a2);
    if(b1>b2) swap(b1,b2);
    int dx=na+b-a;
    int dy=nb+d-c;
    if(min(dx,na)<a1||max(dx,na)>a2||min(dy,nb)<b1||max(dy,nb)>b2||a1==a2&&(a!=0||b!=0)||b1==b2&&(c!=0||d!=0)) puts("No");
    else puts("Yes"); 
}

dx是x方向上的位移,dy是y方向上的位移,
判断一下位移加上初始位置是否超过规定的范围,
由样例可得,需要特判一下x1 == x2 || y1 == y2,
这种情况下要求你在x轴或y轴位移=路程=0,
也就是不允许反复横跳

B. Composite Coloring

题目链接

n<=1000,
第11个质数312=961
第12个质数322=1024
所以至多用11种颜色(其实题目说了)
然后上色就行了

const int maxn=1e3+10;
int n,a[maxn],ans[maxn],color[]={2,3,5,7,11,13,17,19,23,29,31};
void solve()
{
    rd(n);
    int c=0;
    map<int,int>m;
    for(int i=1;i<=n;i++) rd(a[i]);
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=11;j++)
        {
            if(a[i]%color[j]==0)
            {
                if(m[j]==0)
				{
					ans[i]=++c;
					m[j]=c;
				}
				else 
					ans[i]=m[j];
                break;
            }
        }
    }
    cout<<c<<endl;
    for(int i=1;i<=n;i++) cout<<ans[i]<<' ';
    cout<<endl;
}

C. K-Complete Word

题目链接
分循环奇数次和偶数次两种情况,
证得要想使s为回文串,
每个循环节也得是回文串。

既然有循环节,很自然会想到分组,
就是将每一个循环节的第i位分成一组,
每一组的字符我们都要将它们变成一样。

那么我们应该将它们变成什么字符,为什么?
题目要求,改变次数最少,
那么我们可以设定一个数组/map来存储
将这组数全变成某个字母的花费

显然,每一组数一共有n/k个,它的花费就是
n/k减去这个字母在这一组数里面的出现次数

因为是回文,所以第i组数与第k-1-i组数必须相同,
即我们需要将第i组和第k-1-i组数的花费加一起,选a-z中花费最小的,将花费加到答案里去,
这里要特判一下中点,也就是i= =k-1-i的时候,
多计算了一次,除以2后直接加到答案里。

int n,k;
string s;
ll ans;
void solve()
{
    rd(n),rd(k);
    cin>>s;
    ans=0;
    for(int i=0;i<=(k-1)/2;i++)
    {
        map<char,int>m;
        for(int j=i,p=k-1-j;j<n&&p<n;j+=k,p+=k) m[s[j]]++,m[s[p]]++;
        for(char j='a';j<='z';j++) m[j]=2*n/k-m[j];
        int minn=inf;
        for(char j='a';j<='z';j++) minn=min(m[j],minn);
        if(i==k-1-i) ans+=minn/2;
        else ans+=minn;
    }
    cout<<ans<<endl;
}

D. Walk on Matrix

题目链接
Bob是一个没有学好dp的学生,
他从起点开始贪心到终点,每一步取到最大值.
学过最基本dp问题(数塔)的人都知道,
dp应该是从最后一步去反推上去
因为你目前这一步拿到最大值,
不代表你最后能拿到最大值,
说不定你这个最大值后面的数特别特别小。
利用这个概念,我们可以构造一个3*3的矩阵,
使他的错误答案为0,正确答案为n。
那么怎么构造呢?
(1,3),(3,1),(3,3)填n,
(2,2)填100000(217的二进制数)
其余位置填11111(218-1的二进制数)
为什么这么填?
因为他是正向来贪心的,
如果aij是一个比与他左边和上面两个数都大的并且每一位全为1的二进制数,左边和上面的数分别为n和100000000(一个远大于n的数并且除了最高位,每一位都是0的二进制数),他会选择100000000,而不是n,所以我们在(3,3)位置放n,
(3,2),(2,3)位置我们让他错误的结果计算出来都是100000000,正确的结果为n,即可
题目要求是1e5,所以取217和218-1

二进制答案(重复0省略,1省略)
在这里插入图片描述

void solve()
{
	rd(n);
	cout<<"3 3"<<endl;
	cout<<"262143 262143 "<<n<<endl;
	cout<<"262143 131072 262143"<<endl;
	cout<<n<<" 262143 "<<n<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值