昨晚闲的无聊,做套水题爽一爽~
A 题目链接:Problem - A - Codeforces
input:
10
YES
yES
yes
Yes
YeS
Noo
orZ
yEz
Yas
XES
output:
YES
YES
YES
YES
YES
NO
NO
NO
NO
NO
题意:
输入一串字符串,如果是 “ yes ” (大小写不限,比如 yEs ,YEs ),输出 YES ,否则输出 NO。
思路:
签到题,每个字符匹配一下对应大小写字符即可。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t;
int main()
{
ios::sync_with_stdio(false);
cin>>t;
string s;
string ss="YES";
string sss="yes";
while(t--)
{
cin>>s;
bool flag=1;
for(int i=0;i<s.length();i++)
{
if(s[i]!=ss[i]&&s[i]!=sss[i])
{
flag=0;
break;
}
}
if(flag)
{
cout<<"YES"<<endl;
}
else
{
cout<<"NO"<<endl;
}
}
return 0;
}
B 题目链接:Problem - B - Codeforces
input:
6
3
ABA
1
A
3
ORZ
5
BAAAA
4
BKPT
10
CODEFORCES
output:
5
2
6
7
8
17
题意:
给一个长度为n的大写字母字符串,每种字母第一次出现时权值为2,否则权值为1,求字符串总权值
思路:
水题,开个bool数组记录一下是否第一次出现,暴力即可,注意每次memset vis数组
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t,n;
bool vis[30];
int main()
{
ios::sync_with_stdio(false);
cin>>t;
string s;
while(t--)
{
memset(vis,0,sizeof vis);
cin>>n;
cin>>s;
int ans=0;
for(int i=0;i<n;i++)
{
if(!vis[s[i]-65])
{
ans+=2;
vis[s[i]-65]=1;
}
else
{
ans++;
}
}
cout<<ans<<endl;
}
return 0;
}
C 题目链接:Problem - C - Codeforces
input:
3
3
9 3 1
3 DDD
4 UDUU
2 DU
2
0 9
9 DDDDDDDDD
9 UUUUUUUUU
5
0 5 9 8 3
10 UUUUUUUUUU
3 UUD
8 UUDUUDDD
10 UUDUUDUDDU
4 UUUU
output:
2 1 1
9 0
0 4 9 6 9
题意:
有一个位数为n的密码锁,每位是0-9,现给出密码锁的最终组合,并给出对每位密码的操作过程(U代表该位数加1,D代表该位数减1,均0-9循环)求最初的密码锁组合是多少
思路:
前几题数据量太小了,直接暴力即可。读到U往下走,读到D往上走,就能反推最初组合,注意取模即可
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=110;
int a[N];
int t,n,k;
int main()
{
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=n;i++)
{
cin>>k;
string s;
cin>>s;
for(int j=0;j<s.length();j++)
{
if(s[j]=='U')
{
a[i]--;
if(a[i]==-1)
{
a[i]=9;
}
}
else
{
a[i]++;
if(a[i]==10)
{
a[i]=0;
}
}
}
}
for(int i=1;i<=n;i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
}
return 0;
}
D 题目链接:Problem - D - Codeforces
input:
3
5
abab
ab
abc
abacb
c
3
x
xx
xxx
8
codeforc
es
codes
cod
forc
forces
e
code
output:
10100
011
10100101
题意:
给出n个小写字母字符串(长度不超过8),问对于字符串 ai (1 <= i <= n ),是否存在 aj ,ak ( 1 <= j , k <= n ),使 ai = aj + ak (此处的“ + ”意为两个字符串拼接)。输出一串长度为n的01串,第 i 位 为1代表字符串 i 可以满足上述要求,0反之。
思路:
题干中指出的字符串长度不超过8非常关键,意味着我们可以直接暴力将一个字符串拆成两段,然后分别在字符串集合中匹配。开局直接将字符串存入set,然后对于每次拆分,用 set.count() ,查询是否存在即可,复杂度为 O( nlogn )级别。
注意每次set.clear()!
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
int t,n;
string s[N];
int main()
{
ios::sync_with_stdio(false);
cin>>t;
set<string> st;
while(t--)
{
cin>>n;
st.clear();
string ans="";
for(int i=1;i<=n;i++)
{
cin>>s[i];
st.insert(s[i]);
}
for(int i=1;i<=n;i++)
{
bool flag=0;
for(int j=0;j<s[i].length();j++)
{
string a=s[i].substr(0,j);
string b=s[i].substr(j);
if(st.count(a)&&st.count(b))
{
flag=1;
break;
}
}
cout<<flag;
}
cout<<endl;
}
return 0;
}
E 题目链接:Problem - E - Codeforces
input:
5
3
010
110
010
1
0
5
11100
11011
01011
10011
11000
5
01000
10101
01010
00010
01001
5
11001
00000
11111
10110
01111
output:
1
0
9
7
6
题意:
给出形状为 n * n 的 正方形格子,每个格子的值为0或者1,现需令该正方形旋转0°,90°,180°,270°的形状均完全一致。每次可以对一个格子的值进行修改(1变0,0变1)。问最少需要修改多少次,可以满足上述要求。
思路:
n的数据量为100,完全可以在 O( n ^ 2 )复杂度内实现算法,所以直接找规律暴力。
观察可以发现,每个格子 a[i][j] 经过三次旋转,与其对应的位置为:
a[j][n-i+1] , a[n-i+1][n-j+1] , a[n-j+1][i]
所以,直接遍历左上半的1/4块部分,对其三次旋转后的位置进行处理,看全改为0,全改为1哪个代价最小。
对于n为奇数的情况,我们需要对 n / 2 + 1的部分(即最中央的十字架)进行特判处理,处理方式同上。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=110;
int a[N][N];
int t,n;
int main()
{
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
cin>>n;
char c;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>c;
a[i][j]=c-48;
}
}
int ans=0;
for(int i=1;i<=n/2;i++)
{
for(int j=1;j<=n/2;j++)
{
int k=a[i][j]+a[j][n-i+1]+a[n-i+1][n-j+1]+a[n-j+1][i];
ans+=min(k,4-k);
}
}
if(n%2)
{
for(int i=1;i<=n/2;i++)
{
int k=a[n/2+1][i]+a[n/2+1][n-i+1]+a[i][n/2+1]+a[n-i+1][n/2+1];
ans+=min(k,4-k);
}
}
cout<<ans<<endl;
}
return 0;
}
F 题目链接:Problem - F - Codeforces
input:
5
8
1 1 2 3 8 2 1 4
2
1 2
10
0 2 1 6 3 4 1 2 8 3
2
1 1000000000
3
0 1000000000 2
output:
3
0
10
0
1
题意:
给定长度为n的数组a,寻找所有 ai , aj组合, 令 ai < i < aj < j ,输出这个数
思路:
先处理一遍输入,保留 所有 ai < i , 开两个数组分别记录一下 满足要去的 id 和 val ,对 val 数组进行sort,然后 对 id 数组的每个元素在 val 数组中 upper_bound 一下,记录位置为k,则当前第 i 个元素,对其满足 ai < i < aj < j 的 aj 有 cnt - k + 1个,每次记录答案
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
int t,n;
ll a[N],val[N],id[N];
int main()
{
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
cin>>n;
int cnt=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]<i)
{
id[++cnt]=i;
val[cnt]=a[i];
}
}
sort(val+1,val+cnt+1);
ll ans=0;
for(int i=1;i<=cnt;i++)
{
ll k=upper_bound(val+1,val+cnt+1,id[i])-val;
ans+=cnt-k+1;
}
cout<<ans<<endl;
}
return 0;
}
G 题目链接:Problem - G - Codeforces
input:
5
4 5
10 10 3 1
1 2
1
3 12
10 10 29
12 51
5 74 89 45 18 69 67 67 11 96 23 59
2 57
85 60
output:
11
0
13
60
58
题意:
现有n个箱子,第 i 个箱子中含有 ai 个硬币,现需按1-n的顺序开箱。给定一个k,可以每次花费k个硬币的代价开一次箱子,称为 Goodkey ,也可令 ai ,ai+1, …… , an均减半,来打开 第 i 个箱子,称为 Badkey. 开箱过程中可以存在负债情况。问开完所有箱子之后,最多能获得多少硬币
思路:
思维题。分析题意,我们可以得到以下结论:一旦使用了badkey,后面所有箱子都要使用badkey来开启才能保证最优。
证明:对于任意 i ,i + 1 ( 1 <= i <= n-1 )
先goodkey,后badkey,获得的金币数为 a[i] - k + a[i+1] / 2
先badkey,后goodkey,获得的金币数为 a[i] / 2 + a[i+1] / 2 - k
显然情况1收益大于情况2,证毕
又因为 ai不超过1e9,所以最多badkey30次后,后面的所有数就变0了,就不用管了
所以消耗 O(30 * n )的复杂度可以完成操作
遍历 n 次,每次从i开始,ans加上 i-1 的前缀和,减去 k * ( i - 1 ) , 然后向后遍历30次(指针不超过n)每次做badkey,并加入ans,每次对 i 的遍历后,取最大的ans
切记与答案有关的运算,变量均开 long long!!!因为这个点 wa 了两发,气!
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
ll t,n=0,k;
ll a[N];
ll s[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--)
{
for(int i=1;i<=n;i++)
{
s[i]=0;
}
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i];
s[i]=s[i-1]+a[i];
}
ll maxans=0;
for(ll i=1;i<=n+1;i++)
{
ll ans=s[i-1]-k*(i-1);
for(ll j=i;j<=i+30&&j<=n;j++)
{
ans+=ll(a[j]/pow(2,j-i+1));
}
maxans=max(ans,maxans);
}
cout<<maxans<<endl;
}
return 0;
}