数学
一般把整体的框架写出来之后,提交答案时总会感觉少了几个东西,所以在做样例题或者是数学题时需要考虑周全,每个情况都需要考虑到,比如
链接: link.
先排序
排序后开个长度为3的数组记录下不重复的3个数,记录完之后就跳出遍历;
如果不重复的数字只有一个,满足 ai + D,ai - D,ai不变,只有D=0满足;
不重复的数字有两个,相减后看差是偶数还是奇数,差是偶数求半,差是奇数不动;
不重复的数字有3个,最大的减中间的与中间的减最小的是否相等,相等输出差,否则输出-1;
如下
#include<iostream>
#include<cstring>
#include<set>
using namespace std;
set<int> se;
int main()
{
int n;
cin>>n;
int t[3],a[n];
for(int i=0;i<n;i++){
cin>>a[i];
se.insert(a[i]);
}
sort(a,a+n);
t[0]=a[0];
int pos=1;
for(int i=1;i<n;i++){
if(a[i]!=a[i-1])
{
t[pos]=a[i];
pos++;
}
if(pos==3) break;
}
if(se.size()==1)
cout<<"0"<<endl;
else if(se.size()==2){
if((t[1]-t[0])%2==0)
cout<<(t[1]-t[0])/2<<endl;
else cout<<t[1]-t[0]<<endl;
}
else if(se.size()==3) {
if((t[1]-t[0])==(t[2]-t[1]))
cout<<t[1]-t[0]<<endl;
else cout<<"-1"<<endl;
}
else
cout<<"-1"<<endl;
return 0;
}
两两配对时的尴尬问题
链接: link.
两两配对一般是余数配对,一般是先把各项对 k 的余数是 0 ~ k-1 放到map里面,配对时需要注意遍历余数时若有配对残缺,求最小配对数即可,即 min(map[i] , map[k-i]) ;
还有 k 为偶数,那么当i为 k/2 或者 0 时, i , k-i,就相等了,配对数为 map[i]/2;
当 k 为奇数时,只需考虑 i=0的情况;
如下
#include<iostream>
#include<map>
using namespace std;
map<int,int> m;
int main()
{
int k,n,t;
cin>>n>>k;
for(int i=0;i<n;i++){
cin>>t;
t=t%k;
m[t]++;
}
int res=0;
for(int i=0;i<k;i++) {
if(k%2==0){
if(i==k/2 || i==0)
res+=(m[i]/2)*2;
else
res+=min(m[i],m[k-i]);
}
else{
if(i==0)
res+=(m[i]/2)*2;
else
res+=min(m[i],m[k-i]);
}
}
cout<<res<<endl;
return 0;
}
关于前缀和的坑
链接: link.
涉及到求偶数前缀和,奇数后缀和的问题,如果只给一个数字就尴尬了;
需要优先考虑一个数字的情况;
#include<iostream>
using namespace std;
int main()
{
int x,n;
cin>>n;
int s=0,a[3][n];
for(int i=0;i<n;i++){
cin>>a[0][i];
s+=a[0][i];
}
if(n==1) {
cout<<"1"<<endl;
return 0;
}
a[1][0]=0;
for(int i=1;i<n;i++){
if(i%2!=0)
a[1][i]=a[0][i]+a[1][i-1];
else
a[1][i]=a[1][i-1];
} // 偶数项前缀和
a[2][n-1]=((n-1)%2==0? a[0][n-1]:0);
for(int i=n-2;i>=0;i--){
if(i%2==0)
a[2][i]=a[0][i]+a[2][i+1];
else
a[2][i]=a[2][i+1];
} // 奇数项后缀和
int k=0,t;
for(x=0;x<n;x++)
{
int res=s-a[0][x];
if(x==0)
t=a[2][x+1];
else if(x==n-1)
t=a[1][x-1];
else
t=a[1][x-1]+a[2][x+1];
if(res==2*t) k++;
}
cout<<k<<endl;
return 0;
}
二进制中的尴尬问题
链接: link.
注意一点,最初输入数字为0还是1,取决于0多还是1的数目多,不然就会运行出错
#include<iostream>
#include<vector>
using namespace std;
vector<int> v;
int main()
{
int a,b,x,up;
cin>>a>>b>>x;
if(a>b){
v.push_back(0);
a--;
up=0;
}
else{
v.push_back(1);
b--;
up=1;
}
for(int i=0;i<x;i++){
if(up==1){
v.push_back(0);
a--;
up=0;
}
else{
v.push_back(1);
b--;
up=1;
}
}
// for(int i=0;i<v.size();i++) cout<<v[i];
if(up==1){
v.pop_back();
while(a--) v.push_back(0);
v.push_back(1);
while(b--) v.push_back(1);
}
else{
v.pop_back();
while(b--) v.push_back(1);
v.push_back(0);
while(a--) v.push_back(0);
}
for(int i=0;i<v.size();i++) cout<<v[i];
cout<<endl;
return 0;
}
输出时左右为难
链接: link.
B. Obtaining the String
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
You are given two strings s and t. Both strings have length n and consist of lowercase Latin letters. The characters in the strings are numbered from 1 to n.
You can successively perform the following move any number of times (possibly, zero):
swap any two adjacent (neighboring) characters of s (i.e. for any i={1,2,…,n−1} you can swap si and si+1).
You can’t apply a move to the string t. The moves are applied to the string s one after another.
Your task is to obtain the string t from the string s. Find any way to do it with at most 104 such moves.
You do not have to minimize the number of moves, just find any sequence of moves of length 104 or less to transform s into t.
Input
The first line of the input contains one integer n (1≤n≤50) — the length of strings s and t.
The second line of the input contains the string s consisting of n lowercase Latin letters.
The third line of the input contains the string t consisting of n lowercase Latin letters.
Output
If it is impossible to obtain the string t using moves, print “-1”.
Otherwise in the first line print one integer k — the number of moves to transform s to t. Note that k must be an integer number between 0 and 104 inclusive.
In the second line print k integers cj (1≤cj<n), where cj means that on the j-th move you swap characters scj and scj+1.
If you do not need to apply any moves, print a single integer 0 in the first line and either leave the second line empty or do not print it at all.
Examples
inputCopy
6
abcdef
abdfec
outputCopy
4
3 5 4 5
inputCopy
4
abcd
accd
outputCopy
-1
Note
In the first example the string s changes as follows: “abcdef” → “abdcef” → “abdcfe” → “abdfce” → “abdfec”.
In the second example there is no way to transform the string s into the string t through any allowed moves.
看这道题的输出,第一行先输出移动的步数,第二行输出每次移动元素的索引,既然不能移动索引分步输出,那么可以用数组先记录下标,后面一次性输出
问题来了,数组开多大呢,输出多少个呢,很明显,开的数组一定要大,输出只要输够就行,该题只要输出ans个就行,开N个长度的数组;
而且在统计数组实际长度时,其实是不能统计的,不能用strlen()函数,size(),length()函数,,,这容易跟字符串的用法搞混,以上的都是字符串的功能,数组不能用
见代码
#include<iostream>
#include<cstring>
using namespace std;
const int N=1e4+10;
string s,t;
int main()
{
int n;
cin>>n>>s>>t;
for(int i=0;i<n;i++){
m1[s[i]]++;
m2[t[i]]++;
}
for(int i=0;i<n;i++){
if(m1[s[i]]!=m2[s[i]])
{
cout<<"-1"<<endl;
return 0;
}
}
int pos[N],ans=0,p=0;
for(int i=0;i<n;i++){
if(s[i]!=t[i]){
for(int j=i+1;j<n;j++)
{
if(s[j]==t[i])
{
ans+=(j-i);
while(j>=i+1){
swap(s[j-1],s[j]);
pos[p]=j;
p++;
j--;
}
break;
}
}
}
}
cout<<ans<<endl;
for(int i=0;i<ans;i++)
cout<<pos[i]<<" ";
return 0;
}
这道题也可归结为for()循环的见好就收,顾名思义,遍历的终点不一定是数组的末端,或是很长,看题目要求