B. Minimum Ternary String
题意:给了只含0,1,2的字符串,相邻的0和1、1和2可以交换,0和2不能交换,求可以交换成的字典序最小的字符串。
分析:贪心,小的放到大的数前面,0不能放到2前面,以第一个2为基准,它后面的1都放在它前面,它前面的0最前面,前面的1和后面的1是在一起的
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
char s[maxn];
int main()
{
scanf("%s",s);
int len = strlen(s);
int pos = -1;
for(int i = 0; i < len; i++)
{
if(s[i] == '2')
{
pos = i;
break;
}
}
if(pos == -1)
{
for(int i = 0; i < len; i++)
{
if(s[i] == '0')
printf("0");
}
for(int i = 0; i < len; i++)
{
if(s[i] == '1')
printf("1");
}
printf("\n");
}
else
{
for(int i = 0; i < pos; i++)
{
if(s[i] == '0')
printf("0");
}
for(int i = 0; i < len; i++)
{
if(s[i] == '1')
printf("1");
}
for(int i = pos; i < len; i++)
{
if(s[i] == '0')
printf("0");
else if(s[i] == '2')
printf("2");
}
printf("\n");
}
return 0;
}
C. Annoying Present
题意:有n个数,m组系数对,每组系数对包括x和d,其中d需要乘以一个距离和,这个距离和等于 ∑|i - j| (1 =< j <= n,i为选定的坐标),求(d1* ∑|i - j| + d2 * ∑|i - j| + ... dm * ∑|i - j|)/n + x1 + x2+ ... +xm的最大值
分析:根据所给的di的正负选取不同的∑|i - j|,正数选择的肯定是最大的,负数选择的肯定是最小的,最大的选的基准点i就是最边上,最小的选择基准点i在中间
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
char s[maxn];
int main()
{
int n,m;
cin>>n>>m;
int x = n / 2 + 1;
ll d1 = 0,d2 = 0;
for(int i = 1; i <= n; i++)
d1 += abs(x - i);
for(int i = 1; i <= n; i++)
d2 += abs(n - i);
ll sum = 0,ans = 0;
for(int i = 1; i <= m; i++)
{
int a,b;
cin>>a>>b;
sum += a;
if(b >= 0)
{
ans += (d2 * b);
}
else
{
ans += (d1 * b);
}
}
double res = 1.0 * sum + ans * 1.0 / n;
printf("%.7f\n",res);
return 0;
}
D. Relatively Prime Graph
题意:给了n和m,代表有n个顶点和m条边,求能否构建出一个联通图,使得这个图的相邻的顶点互素
分析:因为n和m的范围都是1e5,利用n直接暴力肯定超时,连通图(简单图)边数最多为n * (n - 1) / 2,所以m为1e5时一定不需要1e5个顶点,通过打表发现只需要不超过1000个顶点就够了,n的上限是1000,直接暴力
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
ll a[maxn];
vector<pair<int,int> >edge;
void dabiao()
{
int n = 1;
ll sum = 0;
while(n * (n - 1) / 2 - sum <= 1e5)
{
for(int i = 2; i <= n; i++)
a[i] = n / i;
sum = 0;
for(int i = 1; i <= n; i++)
{
sum += (a[i] * (a[i] - 1)) / 2;
}
cout<<n * (n - 1) / 2 - sum<<endl;
n++;
}
cout<<n<<endl;
}
int main()
{
int n,m;
cin>>n>>m;
if(m < n - 1)
{
printf("Impossible\n");
return 0;
}
for(int i = 2; i <= n; i++)
edge.push_back({1,i});
for(int i = 2; i <= min(n,1000); i++)
{
for(int j = i + 1; j <= min(n,1000); j++)
{
if(__gcd(i,j) == 1 && (int)edge.size() < m)
edge.push_back({i,j});
}
}
if((int)edge.size() < m)
{
printf("Impossible\n");
}
else
{
printf("Possible\n");
for(int i = 0; i < m; i++)
printf("%d %d\n",edge[i].first,edge[i].second);
}
return 0;
}