A:​http://codeforces.com/contest/1399/problem/A

解析:

不多说了,直接sort,判是否存在相邻差>1

#include<iostream>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
typedef long long ll;
const int maxn=60;
int l[maxn],r[maxn];
char ch[3*maxn];
int a[maxn];
int pos[maxn];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
if(n==1)
{
cout<<"YES"<<endl;continue;
}
sort(a+1,a+1+n);
int ok=0;
for(int i=2;i<=n;i++)
if(abs(a[i]-a[i-1])>1)
{
ok=1;break;
}
if(ok)
cout<<"NO"<<endl;
else
cout<<"YES"<<endl;
}
}

B:​http://codeforces.com/contest/1399/problem/B

题意:

长度为n的a[]和b[]

三种操作:

1. ai--

2. bi--

3. ai和bi同时减1

分别把a[]和b[]变成全相等数组,问最少需要的操作数。a[]不一定要和b[]相等。

解析:

因为只存在自减操作,所以元素并不会增大。所以最少需要的操作,一定是a[]和b[]变成对应的最小值。

所以先找到各自的最小值。

遍历a[]和b[],对于每一个ai,bi,算出俩差值,先同时减,然后较大的再自减就可以了。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<stack>
#include<map>
using namespace std;
typedef long long ll;
const int maxn=60;
const int mod=1e9+7;
int l[maxn],r[maxn];
char ch[3*maxn];
ll a[maxn];
ll b[maxn];
ll c[maxn],d[maxn];
int pos[maxn];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
map<ll,ll>m1;
map<ll,ll>m2;
int tot1=0,tot2=0;
ll mina=mod,minb=mod;
for(int i=1;i<=n;i++)
{
cin>>a[i];
mina=min(a[i],mina);
}
for(int i=1;i<=n;i++)
{
cin>>b[i];
minb=min(b[i],minb);
}
ll cnt=0;
for(int i=1;i<=n;i++)
{
int m1=a[i]-mina;
int m2=b[i]-minb;
if(m1>m2)
{
cnt+=m2;
cnt+=m1-m2;
}
if(m1==m2)
cnt+=m1;
if(m1<m2)
{
cnt+=m1;
cnt+=m2-m1;
}
}
cout<<cnt<<endl;
}
}

C:​http://codeforces.com/contest/1399/problem/C

题意:

有n个人想参加划船比赛。第i个参与者的权重是wi。

只有两人组成的团队可以参加比赛。

如果有k个团队(a1,b1),(a2,b2),…,(ak,bk),其中ai是第i个团队的第一个参与者的权重,bi是第二个团队的权重第i个团队的参与者,则必须满足条件a1 + b1 = a2 + b2 =⋯= ak + bk = s,其中s是每个团队的总权重。问有多少个团队可以参赛。

解析:

n==50,直接三重for暴力遍历每一个和值即可。

先统计不同的两两和,然后对它们进行暴力枚举,看每一个值能组成多少团队,取最大即可。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<stack>
#include<map>
using namespace std;
typedef long long ll;
const int maxn=60;
const int mod=1e9+7;
int l[maxn],r[maxn];
char ch[3*maxn];
int a[maxn];
int b[8*maxn];
int vis[maxn];
ll c[maxn],d[maxn];
int pos[maxn];
int main()
{
int t;
cin>>t;
while(t--)
{
memset(vis,0,sizeof(vis));
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int tot=0;
map<int,int>m1;
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
int md=a[i]+a[j];
if(!m1[md])
b[tot++]=md;
m1[md]=1;
}
}
int maxx=0;
for(int i=0;i<tot;i++)
{
memset(vis,0,sizeof(vis));
int cnt=0;
int md=b[i];
for(int j=1;j<=n;j++)
{
for(int c=j+1;c<=n;c++)
{
int md2=a[j]+a[c];
if(!vis[j]&&!vis[c]&&md2==md)
{
cnt++;
vis[j]=1;
vis[c]=1;
}
}
}
maxx=max(maxx,cnt);
}
cout<<maxx<<endl;
}
}

D:​http://codeforces.com/contest/1399/problem/D

题意:

给定一个字符串由0/1组成,问最少有几个字符串是01间隔的(010101……或者101010……)。输出最少的个数和每个字符在第几个子字符串。

解析:

是存在贪心思想的。

因为要想个数更少,肯定对于遍历到的每个0,要接到它之前已经存在的0101...上,而不是另开一个新子串,只有之前没得接的时候,才需要另开新子串。

用到两个队列,一个是stack st[2],用来存以0/1结尾的符合条件的子序列编号。

vector用来存每个字符属于第几个子串。

接下来看注释吧:

#include<iostream>
#include<stack>
#include<vector>
using namespace std;
typedef long long ll;
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
string s;
cin>>s;
stack<int>st[2];
vector<int>vv;
int len=s.length();
int all=1;
for(int i=0;i<len;i++)
{
int now=s[i]-'0';
if(st[now^1].empty()) //now对应的字符,如果没得接,就新开一个子串
{
st[now^1].push(all++);
}
int top=st[now^1].top(); //找到s[i]可以接的子串编号
vv.push_back(top); //存入s[i]所属子串编号
st[now^1].pop(); // 现在的第top子串,已经接上了s[i],那么它的末尾就变了, 0->1/1->0,所以要把top传过去
st[now].push(top);
}
all--;
cout<<all<<endl;
for(int i=0;i<vv.size();i++)
cout<<vv[i]<<" ";
cout<<endl;
}
}