C. Removing Smallest Multiples
筛倍数
题意:给定n,集合S里有从1到n总共n个数,给定一个长度为n的字符串表示集合T,s[i]=1则i在T中存在,s[i]=0则不存在, 把S改成T,每次可以选S中存在的数k,然后删除k的最小倍数,这样操作花费为k,求S变成T的最小花费
题解:两层循环,外层从1枚举到n,每次 枚举i的倍数,如果这个数在T中不存在并且之前没有删掉过这个数(s[j]!=2), 就以i为花费删掉这个数,并把s[j]标记为2,如果存在就停止。
#include<iostream>
#include<cstring>
#include<algorithm>
#include <queue>
#include <map>
#include <cmath>
#include <set>
#include <vector>
#define x first
#define y second
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N=1e6+10;
char s[N];
/*
题意:给定n,集合S里有从1到n总共n个数,给定一个长度为n的字符串表示集合T,s[i]=1则i在T中存在,s[i]=0则不存在,
把S改成T,每次可以选S中存在的数k,然后删除k的最小倍数,这样操作花费为k,求S变成T的最小花费
题解:两层循环,外层从1枚举到n,每次 枚举i的倍数,如果这个数在T中不存在并且之前没有删掉过这个数(s[j]!=2),
就以i为花费删掉这个数,并把s[j]标记为2,如果存在就停止。
*/
void solve()
{
int n; cin>>n;
scanf("%s",s+1);
int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n&&s[j]!='1';j+=i)
{
ans+=i*(s[j]!='2');
s[j]='2';
}
}
printf("%lld\n",ans);
}
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);cout.tie(0);
int t=1; cin>>t;
while(t--)
{
solve();
}
return 0;
}
B. Meeting on the Line
浮点二分
题意:有n个人要到一个地方集合,每人要从a[i]出发,出发前要打扮t[i]分钟,走一单位的距离要花费1时间,求最合适的集合的位置,使得集合时间最短题解:二分位置肯定是不可以的,因为它两边的性质一样,但是可以二分时间,这样每个点都会有一个在这个时间内能够到达的区间范围,求出所有点的区间范围的交集,没有交集就需要一个更大的时间让他们有交集,否则就找有没有更小的时间,最终的交集会趋近于一个点,这个点就是最终答案
#include<iostream>
#include<cstring>
#include<algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#define x first
#define y second
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N=1e5+10;
double ans;
double a[N],t[N];
int n;
/*
浮点二分
题意:有n个人要到一个地方集合,每人要从a[i]出发,出发前要打扮t[i]分钟,走一单位的距离要花费1时间,求
最合适的集合的位置,使得集合时间最短
题解:二分位置肯定是不可以的,因为它两边的性质一样,但是可以二分时间,这样每个点都会有一个在这个时间内能够到达的区间范围,
求出所有点的区间范围的交集,没有交集就需要一个更大的时间让他们有交集,否则就找有没有更小的时间,
最终的交集会趋近于一个点,这个点就是最终答案
*/
bool check(double mid)
{
double l=-2e18,r=2e18;
for(int i=1;i<=n;i++)
{
if(t[i]>mid) return false;
l=max(l,a[i]-(mid-t[i]));
r=min(r,a[i]+mid-t[i]);
}
if(r-l>=1e-8) ans=l;
return r-l>=1e-8;
}
void solve()
{
ans=0;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>t[i];
double l=0,r=2e18;
for(int i=0;i<100;i++)
{
double mid= (l+r)/2.0;
if(check(mid)) r=mid;
else l=mid;
}
printf("%.8lf\n",fabs(ans));
}
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);cout.tie(0);
int t=1; cin>>t;
while(t--)
{
solve();
}
return 0;
}
C. Game Master
贪心
题意: n个人对战n-1局,每个人有两个数ai,bi,每个回合任意挑选两个人的任意值,数字大的人获胜,最终留下一个人胜利,问每个人是否有能赢的可能,有输出1没有0
题解:先对每个人的第一个数从大到小排序,第一个位置必定能赢,然后比较b, 先记录第一个数的b,now=b,再往后寻找,如果有一个位置的b大于now,那么从now那个位置到此处的位置都可以赢,将now重新为从起始位置到此位置的最小值, 继续寻找,直至没有位置的b比now更大
#include<iostream>
#include<cstring>
#include<algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#define x first
#define y second
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N=1e5+10;
typedef struct node
{
int a,b,id;
}DATE;
DATE stu[N];
int ans[N];
bool cmp(DATE l,DATE r)
{
return l.a >r.a ;
}
void solve()
{
/*
贪心
题意: n个人对战n-1局,每个人有两个数ai,bi,每个回合任意挑选两个人的任意值,数字大的人获胜,最终留下一个人胜利,
问每个人是否有能赢的可能,有输出1没有0
题解:先对每个人的第一个数从大到小排序,第一个位置必定能赢,然后比较b, 先记录第一个数的b,now=b,再往后寻找,
如果有一个位置的b大于now,那么从now那个位置到此处的位置都可以赢,将now重新为从起始位置到此位置的最小值,
继续寻找,直至没有位置的b比now更大
*/
int n; cin>>n;
for(int i=1;i<=n;i++)
{
stu[i].id=i; ans[i]=0; cin>>stu[i].a;
}
for(int i=1;i<=n;i++) cin>>stu[i].b;
sort(stu+1,stu+1+n,cmp);
int now=stu[1].b,t=stu[1].b;
int id=1;
for(int i=2;i<=n;i++)
{
if(stu[i].b >now)
{
id=i;
now=min(now,t);
}
else t=min(t,stu[i].b);
}
for(int i=1;i<=id;i++) ans[stu[i].id]=1;
for(int i=1;i<=n;i++)
{
cout<<ans[i];
}
cout<<"\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t=1; cin>>t;
while(t--)
{
solve();
}
return 0;
}