czl蒻蒟的OI之路

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

T1:Odds and Ends (已AC)

题意:
给出一个数列,让你判断这个数列能不能被分成奇数个的小数列,并且每个小数列都必须由奇数开头,由奇数结尾,且个数为奇数个。
分析过程:
既然要奇数开始,奇数结尾,那么数列如果以偶数开始,或者以偶数结尾,就直接PASS掉,输出No就行。
如果数列满足这个条件,那么判断这个数列的个数,如果是偶数个,显然是不行的(奇数个奇数相加等于奇数)。
其他的就都可以了
恩,一点不暴力。
给出题解:
#include <bits/stdc++.h>
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<bits/stdc++.h>
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"<<endl;  
    else  
        cout<<"No"<<endl;  
    return 0;  
} 

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

题意:

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

分析过程:

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

给出题解:
#include<bits/stdc++.h>  
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<bits/stdc++.h>
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<<endl;  
    }  
    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<bits/stdc++.h>
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里程吧。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值