上场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;
}
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反向擦除,见识了奇妙的构造方法,然后还涨了这么多分,挺好的,加油