目录
A. Extremely Round
题意:
给定一个n,要求输出1-n范围内,只含有一个非0数字的个数。
思路:
我的想法是,入手就是找规律,我们可以发现1-9的范围内,有9个数(1-9本身),10-90的范围内有9个数 (10,20,30……90)以此类推,100到900之间也存在9个数,我们可以发现,9的个数,是和n的位数挂钩的,并且最高位为多少,就会多加几个数字。因此我们可以将n的位数求出来,并且求出n的最高位,就可以得到答案。
#include<iostream>
#include<map>
#include<algorithm>
#include<set>
#include<string>
#include<string.h>
#include<math.h>
#include<vector>
typedef long long ll;
const int N=1e5+5;
using namespace std;
typedef pair<int,int> p;
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
int a[N];
int b[N];
int main()
{
int t;
scanf("%d",&t);
while (t--)
{
int n;
cin>>n;
int cnt=0;
if(n<=9){
cout<<n<<endl;
continue;
}
while(n>10){
n/=10;
cnt++;
}
cout<<n+cnt*9<<endl;
}
system("pause");
return 0;
}
其实我们发现,如果是两位数的话,最后的数字为从9开始加,所以位数减一就为9的组数,比如3位数就有2组9,也就是18。此时刚好分解得到最高位,再加上最高位就可以了。
B. Notepad#
题意:
给定一个字符串,并且给出他的长度n(长度也为后文的操作次数),此时你可以进行两种操作:
添加任意一个字母在字符串的尾部;
复制一段已有的字符串到尾部;
问,能不能在 n步操作内,得到题目所说的字符串。
思路:
我们如果一个一个字母打印的话,次数刚好为n,我们为了满足题目的要求,则至少需要在其中一步操作中打印字母的数目大于等于2个,由此则符合题目要求。由此转化为了,是否存在某次打印,符合条件2(并且字符数量大于等于2),因为2是从已经有的字符串中选出一部分,那么说明,该字符串,(如果能成功打印),则一定存在相同的部分。由此我们可以对字符串每个字符进行遍历,两个为一组,存进map,最后遍历map,如果map的value存在大于1的,即是符合要求的字符串。
但需要处理一些小细节,比如样例中的,uohhh,此时hh的出现次数会计为2,但很明细这种情况不符合题目的要求。
还有一处就是,aaaas这种,因为按照上文中所说,当相同的字母相连时,我们是不算入次数的。所以最后对于这种需要重新进行计算。
#include<iostream>
#include<map>
#include<algorithm>
#include<set>
#include<string>
#include<string.h>
#include<math.h>
#include<vector>
typedef long long ll;
const int N=1e5+5;
using namespace std;
typedef pair<int,int> p;
map<string,int>z;
int main()
{
int t;
scanf("%d",&t);
while (t--)
{
z.clear();
int n;
cin>>n;
string a;
cin>>a;
int i;
string x=a.substr(0,2);
z[x]++;
for(i=1;i<a.size();i++){
string b=a.substr(i,2);
string c=a.substr(i-1,2);//防止uoshhhh的情况
if(c!=b){
z[b]++;
}
}
int flat=0;
for(auto x:z){
if(x.second>=2){
flat=1;
break;
}
}
int cnt=0;
for(i=1;i<a.size();i++){//处理aaaas的情况
if(a[i]==a[i-1]){
cnt++;
if(cnt>=3){
flat=1;
break;
}
}
else{
cnt=0;
}
}
if(flat){
cout<<"YES"<<endl;
}
else{
cout<<"NO"<<endl;
}
}
system("pause");
return 0;
}
C. Hamiltonian Wall
题意:
emmm太长了不想描述,就是给定一个2*n的长方形,然后每一列可能存在两个黑的,或者是一个黑的,这个人走路只能横着走或是竖着走,不能斜着走,问是否可以一次性走完所有黑色格子(不带回头的那种)
思路:
当时想了很久,没什么方法,只能硬着头皮模拟了,模拟的过程也写了好久,可以说大部分时间都花这题上了。
回归思路,既然是模拟,就按题目要求一步步来呗。我们从起点开始,因为考虑到,第一列可能存在两黑的情况,所以我将第一行和第二行这两种情况全部跑了一遍。后面则是定义了一个变量now,来记录当前是到第一行的黑还是第二行的黑。后面完全就是按照题意来了,不知道该怎么描述了,按学长的话来说就是乱搞一下。
#include<iostream>
#include<map>
#include<algorithm>
#include<set>
#include<string>
#include<string.h>
#include<math.h>
#include<vector>
typedef long long ll;
const int N=2e5+5;
using namespace std;
typedef pair<int,int> p;
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
char z[4][N];
int n;
bool solve(int now){
int k=1;
int flat=0;
while(k<n){
int t=now;//避免错误的对now进行修改,即这列只有一个黑,但也会先去改变now看这一列另一个位置,此处就是为了保证下面的if位置不会出错
if(z[now][k]=='B'){
if(now==1){
now=2;
}
else{
now=1;
}
if(z[now][k]=='B'){//两行都是黑的情况
if(z[now][k+1]=='B'){
k++;
continue;
}
else{
break;
}
}
}
else{
break;
}
if(z[t][k+1]=='B'){//这列只有一个黑
k++;
now=t;
continue;
}
else {
break;
}
}
if(k==n){//跑到了最后
return true;
}
else{
return false;
}
}
int main()
{
int t;
scanf("%d",&t);
while (t--)
{
memset(z,0,sizeof(z));
scanf("%d",&n);
int i,j;
int str;
for(i=1;i<=2;i++){
for(j=1;j<=n;j++){
cin>>z[i][j];
}
}
if(solve(1)||solve(2)){//分别跑第一行和第二行
cout<<"YES"<<endl;
}
else{
cout<<"NO"<<endl;
}
}
system("pause");
return 0;
}
D. Lucky Chains
题意:
给定,a,b两个数字,记为一组,分别对其进行加一 ,直到gcd(a,b)不为1,问有多少组这样的(a,b)。(a,b)本身不算。
新增了完全版,应该更透彻一些http://t.csdn.cn/bdZ6y
思路:
这题没写出来,赛后补的,一开始想着+1一个一个枚举,后面问学长这种方法,学长直接否定了,太暴力了,就给了一句话,考虑差值,然后开始从差值入手,自己慢慢在草稿纸上打草稿,发现差值的大小好像跟组数存在某种关系:拿40 37来说,
40 | 37 |
41 | 38 |
42 | 39 |
此时我们可以发现,两个数刚好就能被3整除,而两个数的差值刚好也为3,此时的组数为3是凑巧(自己下去多列举几组),我们猜测,我们可以寻找,差值的最小因子,然后让该因子的倍数恰好大于其中一个数(两个数取谁都一样),比如此时的差值为3,我们寻找恰好为3的倍数的3*13=39,即为我们所求,39再减去37,为2,就是我们要的答案。
但这样是存在一些漏洞的,有可能存在其他的因子,能比最小的因子的倍数更接近。然后,存在时间复杂度的问题,分解质因数,当数据多了后,会tle。
于是我们先预处理一下,求出每个数的最小质因子,再进行其他的操作。
#include<iostream>
#include<algorithm>
#include<vector>
#include<math.h>
using namespace std;
const int SITO_MAX = 10000000;
int f[SITO_MAX+1];
vector<int> prosti;
struct sito {
sito() {//求每个数的最小因子
for (int i=2; i<=SITO_MAX; i++) {
if (f[i] == 0) {
f[i] = i;
prosti.push_back(i);
}
int j = 0;
while (j < (int)prosti.size()) {
if (prosti[j] > f[i]) {
break;
}
int x = i * prosti[j];
if (x > SITO_MAX) {
break;
}
f[x] = prosti[j];
j++;
}
}
}
}
vector<int> factor_small(int x) {//求质因子
vector<int> v;
while (x > 1) {
int p = f[x];
while (x % p == 0) {
x /= p;
}
v.push_back(p);
}
return v;
}
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
int m,n;
scanf("%d%d",&m,&n);
if(gcd(m,n)!=1){
printf("0\n");
}
else {
int x=abs(m-n);
if(x==1){
printf("-1\n");
}
else{
auto z = factor_small(x);
int ans=1e9+5;
int tem;
int i;
for(i=0;i<z.size();i++){
tem=(int)ceil(m*1.0/z[i]);
ans=min(ans,tem*z[i]-m);
}
printf("%d\n",ans);
z.clear();
}
}
}
system("pause");
return 0;
}
也是第一次div2能够写出三题来,之前都是签到选手,d题wa了挺久的,不是wa就是tle,当时看别人的代码,完全看不懂这个预处理什么意思,最后自己打表发现,就是求出每个数的最小因子。然后后面的操作想法什么的都跟自己差不多,但别人写出来了一遍过,自己搞这么久,可能这就是自己跟橙名的差别吧。还是要努力。
中间还差一次div2没有补,cf上没有题解,csdn上也没有,等有了在补吧。
每次一遍,完结撒花。