CF Round #630

CF Round #630

A.模拟

给定一个初位置,现在要分别走上走下走右走左各多少步,再给定一个范围

问能否走成而不超界

大减小,判断下越界即可

最好加上一个特判:左走k,右走k,但是范围有且仅有一个值的情况

B.数学

给定n个合数(1-1000)

你现在至多使用m种颜色对他们染色(m<=11)

使得同种颜色中的任意两个元素他们gcd不为1

输出m,和染色方案

其实这题范围是突破口,理解了范围的内含问题就出来了

n个数是合数,那么你开2,3,5,7,11,13,17,19,23,29,31这11个桶把数往里面丢即可

值得注意染色还要是m种,m个中全都要用,所以还要遍历桶内是否有存元素,遍历映射一个颜色值即可

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define INF 1e10+5
#define maxn 10005
#define minn -105
#define ll long long int
#define ull unsigned long long int
#define uint unsigned int
#define re register
inline int read()
{
    re int t=0;
    re char v=getchar();
    while(v<'0')v=getchar();
    while(v>='0')
    {
        t=(t<<3)+(t<<1)+v-48;
        v=getchar();
    }
    return t;
}
bool ok[11];
int pr[11]={2,3,5,7,11,13,17,19,23,29,31};
int a[maxn];
int color[11];
void solve()
{
    int n;
    int m=0;
    memset(ok,0,sizeof(ok));
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
        for(int j=0;j<11;j++)
        {
            if(a[i]%pr[j]==0)
            {
                a[i]=j;
                ok[j]=1;
                break;
            }
        }
    }
    int cnt=1;
    for(int j=0;j<11;j++)
        {
            if(ok[j])
            {
                color[j]=cnt;
                m++;
                cnt++;
            }
        }
    cout<<m<<endl;


    for(int i=0;i<n;i++)
    {
        cout<<color[a[i]]<<" ";
    }
    cout<<endl;

}
int main()
{
    int t;
    cin>>t;
    for(int i=0;i<t;i++)
    {
        solve();
    }
    return 0;
}

C.数学

给定字符串s,和k,保证k|s,现在问你至少要改多少个字符使得s满足k-complete

思路:其实这题想清楚不难发现,

因为a[jk+i]==a[jk+k-i-1]==a[(j+1)*k+i]

所以所构的字符串无非是一个长为k的回文串,copy了原长/k次而已

现在就是让他的值最小

无非就是统计一下所有长度为k的段中第i号与第k-i-1号字母出现的个数即可

注意遍历方式,第一次遍历i,第二次遍历第j个长为k的段

注意要特判k为奇数的情况

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define INF 1e10+5
#define maxn 200005
#define minn -105
#define ll long long int
#define ull unsigned long long int
#define uint unsigned int
#define re register
inline int read()
{
    re int t=0;
    re char v=getchar();
    while(v<'0')v=getchar();
    while(v>='0')
    {
        t=(t<<3)+(t<<1)+v-48;
        v=getchar();
    }
    return t;
}
char a[maxn<<1];
int cur[34];
void solve()
{
    int len,k;
    cin>>len>>k;
    int ans=len;
    for(int i=0;i<len;i++)
    {
        cin>>a[i];
    }
    for(int i=0;i<k/2;i++)
    {
        memset(cur,0,sizeof(cur));
        int curmax=0;
        for(int j=0;j<len/k;j++)
        {
            cur[a[j*k+i]-'a']++;
            cur[a[j*k+k-i-1]-'a']++;
            curmax=max(curmax, cur[a[j*k+i]-'a']);
            curmax=max(curmax, cur[a[j*k+k-i-1]-'a']);
        }
        ans-=curmax;
    }
    if(k&1)
    {
        memset(cur,0,sizeof(cur));
        int curmax=0;
        for(int j=0;j<len/k;j++)
        {
            cur[a[j*k+k/2]-'a']++;
            curmax=max(curmax, cur[a[j*k+k/2]-'a']);
        }
        ans-=curmax;
    }
    cout<<ans<<endl;
}
int main()
{	
	int t;
	cin>>t;
	for(int i=0;i<t;i++)
	{
	    solve();
	}
	return 0;
}

D.构造

题意是给定一个k,让你构造一个矩阵

从左上角到右下角寻找到一条路径,使得路径上所有数的位和&最大

有人写了个dp算法求解出来答案为u,真实解为u+k

思路:dp的核心就是贪心,它每一步决策是最优最大的。为了使dp出来的值要小于真实答案,其实我们只要让dp因小失大即可

在最后一步时,opt[n-1][m]=0 opt[n][m-1]=x matrix[n][m] =k(x>>k,x&k=0)

这样就因小失大了,接下来只要保证opt[n][m-1]的取值即可

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define INF 1e10+5
#define maxn 105
#define minn -105
#define ll long long int
#define ull unsigned long long int
#define uint unsigned int
#define re register
inline int read()
{
    re int t=0;
    re char v=getchar();
    while(v<'0')v=getchar();
    while(v>='0')
    {
        t=(t<<3)+(t<<1)+v-48;
        v=getchar();
    }
    return t;
}
int main()
{
    ll k;
    cin>>k;
    ll a=1<<17;
    cout<<2<<" "<<3<<endl;
    cout<<k+a<<" "<<k<<" 0"<<endl;
    cout<<a<<" "<<k+a<<" "<<k<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/et3-tsy/p/12610441.html