czl蒻蒟的OI之路

    • XJOI奋斗群蒻蒟群群赛2 RANK排名3
      • T1Odds and Ends 已AC
          • 题意
          • 分析过程
          • 给出题解
      • T2Tell Your World 已AC
          • 题意
          • 分析过程
          • 给出题解
      • T3From Y to Y未AC订正时一次TLE
          • 题意
          • 分析过程
          • 给出题解
      • T4Harmony Analysis WA了两次后AC
          • 题意
          • 题解
          • 给出题解
      • T5Bear and Prime Numbers TLE一次后AC
          • 题意
          • 分析过程
          • 给出题解
      • 蒻蒟的总结

—>XJOI奋斗群(蒻蒟群)群赛2<— RANK排名3

T1:Odds and Ends (已AC)

题意:
给出一个数列,让你判断这个数列能不能被分成奇数个的小数列,并且每个小数列都必须由奇数开头,由奇数结尾,且个数为奇数个。
分析过程:
既然要奇数开始,奇数结尾,那么数列如果以偶数开始,或者以偶数结尾,就直接PASS掉,输出No就行。
如果数列满足这个条件,那么判断这个数列的个数,如果是偶数个,显然是不行的(奇数个奇数相加等于奇数)。
其他的就都可以了
恩,一点不暴力。
给出题解:
#include 
using namespace std;  
int n;  
int a[105];  
int main()  
{  
    int i;  
    scanf("%d",&n);
    for( i=1;i<=n;i++)scanf("%d",&a[i]);  
    if(n%2==0||a[1]%2==0||a[n]%2==0)
        printf("No\n");  
    else 
        printf("Yes\n");  
    return 0;  

T2:Tell Your World (已AC)

题意:

给出几个点,让你判断是否能由两条平行且不重复的直线穿过这所有的点。

分析过程:

利用直线平行,斜率相同(k=(x1-x2)/(y1-y2))。首先先算一下前三个点两两组合的斜率,如果是能够画出两条直线的话,其中必定有一个斜率是真的斜率,分别以这三个点为直线所过的第一个点,计算之后的点和它组成直线的斜率,如果之后的点都能组成一个和原来三个斜率的任意一个的斜率,就返回Yes,如果都不能,就返回No。

给出题解:
#include
using namespace std;  
#define maxn 1000005    
int n;  
int p[1005];  
bool solve(double  k)  
{  
    int flag=0;  
    int point=-1;  
    for(int i=2;i<=n;i++)  
    {  
        if(p[i]-p[1]==k*(i-1))  
            continue;  
        flag=1;  
        if(point<0)  
            point=i;  
        else  if(p[i]-p[point]!=(i-point)*k)  
        {  
            flag=0;  
            break;  
        }  
    }  
    if(flag)  
        return true;  
    else  
        return false;  
}  
int main()  
{  
    cin>>n;  
    for(int i=1;i<=n;i++)cin>>p[i];  
    double k1=(p[2]-p[1])*1.0;  
    double k2=(p[3]-p[2])*1.0;  
    double k3=(p[3]-p[1])*0.5;  
    if(solve(k1)||solve(k2)||solve(k3))  
        cout<<"Yes"<else  
        cout<<"No"<return 0;  
} 

T3:From Y to Y(未AC,订正时一次TLE)

题意:

给你一个操作:选择序列中的两个元素,把它们并成同一个元素,并且计算其贡献值。贡献值就是两个元素中相同的字符串在两个元素中出现的次数的乘积。
然后给出一个数字k,让你输出一个字符串,让他们的最小贡献值之和等于这个数字k。

分析过程:

刚开始很懵,根本不知道贡献值怎么算,也不知道最优的方法怎么弄。然er,吃了个饭,睡了个午觉,就觉得这题好简单。首先,不管无论合并的方法是怎么样的,只要字符串不变,贡献值都是一定的。然后,每个字母的贡献值,就是它在原字符串中出现的次数n,贡献值为n*(n-1)/2。所以只要一次次遍历每个字母的贡献值,让所有字母的贡献值加起来等于k就可以了,然后根据每个字母的个数,输出字符串。

给出题解:
#include  
using namespace std;  
int main()  
{  
    int n;  
    scanf("%d",&n);
        int nowsum=0;  
        for(int i=1;i<=26;i++)  
        {  
            int pos=100;  
            for(int j=1;j<=100;j++)  
            {  
                if(nowsum+j*(j-1)/2>n)  
                {  
                    pos=j-1;  
                    break;  
                }  
            }  
            for(int j=1;j<=pos;j++)printf("%c",i+'a'-1);  
            nowsum+=(pos*(pos-1))/2;  
            if(nowsum==n)break;  
        }  
        printf("\n");  
}

T4:Harmony Analysis (WA了两次后AC)

题意:

简单来说,就是让你编一个2^k的矩阵,让矩阵的每一行的贡献值之和为0。贡献值算法:一个“+”和一个“*”,贡献值为-1,其他的组合贡献值1。

题解:

很简单的想法,普通的递归,先定出边界k=0时,只输出一个“+”,然后把每一个矩阵四分,左上,左下,右上都是填相同的,右下的填上与左上的刚好相反。这样递归,能够满足题意(也不知道自己怎么想出来的)。

给出题解:
#include
using namespace std;  

const int maxn = 530;  

int k;  
int a[maxn][maxn];  

void print(int n, int x, int y, int v)  
{  
    if (n == 1)  
    {  
        a[x][y] = v;  
    }  
    else  
    {  
        print(n/2,x,y,v);  
        print(n/2,x+n/2,y,v);  
        print(n/2,x,y+n/2,v);  
        print(n/2,x+n/2,y+n/2,-v);  
    }  
}  

int main()  
{  
    cin >> k;
    k=pow(2,k);  
    print(k,1,1,1);  
    int i,j;  
    for (i=1;i<=k;i++)  
    {  
        for (j=1;j<=k;j++)  
        {  
            if (a[i][j]==1)  
            {  
                cout<<"+";  
            }  
            else  
            {  
                cout<<"*";  
            }  
        }  
        cout<return 0;  
}  

T5:Bear and Prime Numbers (TLE一次后AC)

题意:

给你一个数组,然后向你询问m次,每次给出li和ri两个值,让你判断f(p)的值,f(p)算法:li到ri的所有质数,列出每个质数所对应的贡献值(贡献值为数组中能够被这个质数整除的个数),然后相加。最后输出f(p)。

分析过程:

首先,f(p)的算法并不复杂,只需简单的模拟即可。重点在于筛质数的方法,很接近与线性筛质数的方法。举个栗子,首先先筛出了2是质数,然后把2的所有倍数都筛掉(因为这些必定都是合数),然后找出大于2的最小的没有被筛掉的数,继续下去。
然后,这样优化还是不够的,如果每次都筛一遍质数,那么会浪费很多的时间和空间。所以我们只需要晒出1~li,1~ri的f(p)的值,然后相减,就能得出最终的f(p)的值。
最后还有一个小优化,设数组的最大值为maxn,如果maxn的值小于ri,那么maxn到ri之间的质数都不用筛了,因为没什么意义(不可能在数组中有数可以被这个质数整除了)。

给出题解:
#include
const int N = 10000005;  

int n, m, v[N], g[N], s[N];  

int main() {  
    memset(v, 0, sizeof(v));  
    memset(g, 0, sizeof(g));  
    memset(s, 0, sizeof(s));  

    int a, b;    
    scanf("%d", &n);  
    for (int i = 0; i < n; i++) {  
        scanf("%d", &a);  
        g[a]++;  
    }  

    for (int i = 2; i < N; i++) {  
        if (v[i]) continue;  
        for (int j = i; j < N; j += i) {  
            if (g[j]) s[i] += g[j];  
            v[j] = 1;  
        }  
    }  
    for (int i = 1; i < N; i++) s[i] += s[i-1];  



    scanf("%d", &m);  
    for (int i = 0; i < m; i++)
    {  
        scanf("%d%d", &a, &b);  
        if (a >= N) a = N;  
        if (b >= N) b = N - 1;  
        printf("%d\n", s[b] - s[a-1]);  
    }   
    return 0;  
}

蒻蒟的总结:

作为蒻蒟第一次写博客,还是比较有纪念意义的,不幻想自己在以后能够拿到金牌什么的,只是想在这个奋斗群(蒻蒟群)里面提升自己。旁边都是大佬,蒻蒟瑟瑟发抖~之后每天都坚持写着博客,应该能够记录下自己的OI里程吧。


你可能感兴趣的:(蒟蒻OI之路)