Codeforces Round #447 (Div. 2)

19 篇文章 0 订阅

上场cf的失利后,感觉急需一场cf来找回自信

然而,这场的情况似乎和上场差不多,由于网速和自己本身提不起精神的原因,将近10min才过了第一题,然后第二题别人也过得特别快,然而我却毫无思路,到将近1h才想明白,感觉这场又要完蛋,这时,大部分人已经过了第三题了,知耻而后勇,赶紧奋起第三题,然而最后还是没能写完交上去,感觉即使写完了,也未必对啊,我似乎太复杂了

然而最终结果,却有点出乎意料了,最终由于所有人的好友全部倒在了c上,估计都是猜结论的,只有我一个人是写vector擦除去模拟的吧,然后至于b也有大部分被fst了,而我踏踏实实写了两题,虽然也只有两题,但居然直线涨粉90+,却是有点惊喜了

那么就来回顾一下涨粉历程吧


A. QAQ

思路:这题却是没什么难度,就是统计a和q,对于每个a,将其前后q个数相乘,最后累加即是结果,那么统计一下q总数和每个a前方的q数,即可得到结果

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <cmath>
#include <string>
#include <queue>
#include <stack>

using namespace std;

const int maxn = 1e3+10;

char qaq[maxn];
int pre[maxn];

int main()
{
    while(scanf("%s",qaq)!=EOF)
    {
        int len = strlen(qaq);
        int sum = 0;
        int n = 0;
        for(int i=0;i<len;i++)
        {
            if(qaq[i]=='Q')
            {
                sum++;
            }
            else if(qaq[i]=='A')
            {
                pre[n++] = sum;
            }
        }
        int re = 0;
        for(int i=0;i<n;i++)
        {
            re += pre[i] * (sum-pre[i]);
        }
        printf("%d\n",re);
    }
    return 0;
}

B. Ralph And His Magic Field

思路:这题的思路就比较巧妙了,但也确实不太好想,迷茫了好久,看大家疯狂过题,心慌,其实淡定即可,相信自己

计算所有单行和单列乘积均为1或-1的方案数,其实,这题所有的值都是1或-1,也就是填充区域只需要考虑符号即可

一开始想的是找找递推关系,然而发现这个关系很复杂,不是简单可以退出来的

然后又想到dp,而过大的数据范围直接将dp否定了

最后偶然想到,可以先统计前n-1行和m-1列的方案数,然后最后一行和一列根据前面进行填充

那么,正负有没有想影响呢?

当然,位于(m,n)位置的元素既要照顾第m行,又要照顾第n列,就有可能出现无法实现的情况,那么什么情况下无法实现呢?

当k为1时,每行-1均为偶数个,每列也均为偶数个,所以总数一定为偶数。那么,根据对应原则,行列奇偶性应该是相同的,那么一定可以时间

而当k为-1时,每行-1均为奇数个,每列也均为奇数个,而当行列奇偶性不同时,就会导致必存在行或列与总数奇偶性不同,这个必定无法时间

排除这个特殊情况后,其余的数取2^(n-1)*(m-1)就好了,由于指数过大,一开始还想着欧拉降幂,后来发现先算a=2^(n-1),再算b=a^(m-1)就好了

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <cmath>
#include <string>
#include <queue>
#include <stack>

using namespace std;

const int maxn = 1e5+10;
const long long mode = 1e9+7;

long long Power(long long a0,long long k)//a0^k%mode
{
	long long b0;
	if(k==0)
		return 1;
	if(k==1)
		return a0 % mode;
	else if(k%2==0)
	{
		b0=Power(a0,k/2);
		return (b0%mode)*(b0%mode)%mode;
	}
	else
	{
		b0=Power(a0,k-1);
		return (b0%mode)*(a0%mode)%mode;
	}
}


int main()
{
    long long n,m,k;
    while(scanf("%I64d%I64d%I64d",&n,&m,&k)!=EOF)
    {
        if((k==(-1))&&((n+m)%2LL==1LL))
        {
            printf("%d\n",0);
        }
        else
        {
            long long re = Power(2LL,n-1);
            re = Power(re,m-1);
            printf("%d\n",re);
        }
    }
    return 0;
}


两题到手,殊不知现在的自己已经走在了疯狂涨粉的道路上,看着伙伴们仍在拼命过题,赶紧转战c题,心中内心恐惧不已

其实c是个智商题,编程上基本没有难度,就是思维确实比较有难度的

C. Marco and GCD Sequence

思路:这题就是个典型的构造,本来的思路是,将大数向前摆放,后面如果可以被整除就可以不往数组中添加了,然而这样确实对数组的顺序没什么办法,完全卡在了判断数组成立上了

然而正解思路是,想一种很巧妙的构造方式,由于数组有序,那么第一个元素必定是公约数,那么只要将所有元素之间插入该元素,那么就可以保证所有中间结果,要么是元素本身,要么就是该元素,保证了不会有新元素生成。

想到了这种构造方式,一切就都豁然开朗了,于是剩下的任务就是判断第一个元素是否为公约数,如果是,就按照这种方式构造,否则输出-1

或许这就是构造题的典型技巧与神秘之处了吧

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <cmath>
#include <string>
#include <queue>
#include <stack>
#include <cmath>

using namespace std;

const int maxn = 1e6+10;
/*
vector <int> s;
bool in[maxn];
bool comp[maxn];
vector <int> a;
vector <int> g;
*/
int a[1010];

int gcd(int a,int b)
{
	return b == 0 ? a : gcd(b, a % b);
}

int main()
{
    int m;
    while(scanf("%d",&m)!=EOF)
    {
        bool canmake = true;
        for(int i=0;i<m;i++)
        {
            scanf("%d",&a[i]);
            if(a[i]%a[0]>0)
            {
                canmake = false;
            }
        }
        if(canmake)
        {
            printf("%d\n",2*m-1);
            printf("%d",a[0]);
            for(int i=1;i<m;i++)
            {
                printf(" %d %d",a[0],a[i]);
            }
            printf("\n");
        }
        else
        {
            printf("-1\n");
        }
        /*memset(in,false,sizeof(in));
        memset(comp,false,sizeof(comp));
        int sum = 0;
        s.clear();
        a.clear();
        g.clear();
        for(int i=0;i<m;i++)
        {
            int temp;
            scanf("%d",&temp);
            s.push_back(temp);
            in[temp] = true;
        }
        vector <int> :: reverse_iterator it;
        while(!s.empty())
        {
            //cout << sum << "*" << endl;
            for(it = s.rbegin();it!=s.rend();)
            {
                if(comp[*it])
                {
                    it = vector<int>::reverse_iterator(s.erase((++it).base()));
                }
                else
                {
                    int pos = 0;
                    for(;pos<sum;pos++)
                    {
                        if(!in[gcd((*it),g[pos])])
                        {
                            break;
                        }
                    }
                    //cout << pos << "**" << sum << "**" << a.size() << endl;
                    if(pos==sum)
                    {
                        a.push_back(*it);
                        sum++;*/
                        /*for(int i=0;i<sum-1;i++)
                        {
                            printf("%d ",a[i]);
                        }
                        printf("%d\n",a[sum-1]);*/
                        /*g.push_back(*it);
                        for(pos=0;pos<sum;pos++)
                        {
                            g[pos] = gcd((*it),g[pos]);
                            comp[*it] = true;
                            comp[g[pos]] = true;
                            it = vector<int>::reverse_iterator(s.erase((++it).base()));
                            break;
                        }
                    }
                    else
                    {
                        it++;
                    }
                    //it++;
                }
            }
            if(it == s.rend()&&(!s.empty()))
            {
                sum = -1;
                break;
            }
        }
        printf("%d\n",sum);
        if(sum>0)
        {
            for(int i=0;i<sum-1;i++)
            {
                printf("%d ",a[i]);
            }
            printf("%d\n",a[sum-1]);
        }*/
    }
    return 0;
}


最后补一个小tip吧,关于vector反向迭代器和擦除

vector <int> :: reverse_iterator it;
for(it = s.rbegin();it!=s.rend();)
{
    if(/*擦除*/)
    {
        it = vector<int>::reverse_iterator(s.erase((++it).base()));
    }
    else
    {
        it++;
    }

}
这场算是皆大欢喜了,掌握了vector反向擦除,见识了奇妙的构造方法,然后还涨了这么多分,挺好的,加油


文章地址:http://blog.csdn.net/owen_q/article/details/78630170

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值