2021年度训练联盟热身训练赛第一场

A Weird Flecks, But OK
最小圆覆盖模板题,大部分都是用的板子吧,来个三分套三分吧。(跑得比较慢)

#include 
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const double eps=1e-6;
const int N = 5010, M = 1e6+10;
int n,k;
double x[N],y[N],z[N];

double check3(double a,double b,double x[],double y[]){
     
    double res=0;
    for(int i=1;i<=n;++i){
     
        res=max(res,sqrt((a-x[i])*(a-x[i])+(b-y[i])*(b-y[i])));
    }
    return res;         
}

double check2(double a,double x[],double y[]){
     
    double l=-1e3,r=1e3;
    while(r-l>eps){
     
        double mid1=l+(r-l)/3;
        double mid2=r-(r-l)/3;
        if(check3(a,mid1,x,y)<check3(a,mid2,x,y)) r=mid2;
        else l=mid1;
    }
    return check3(a,l,x,y);
}

double check(double x[],double y[])
{
     
    double l=-1e3,r=1e3;
    while(r-l>eps){
     
        double mid1=l+(r-l)/3;
        double mid2=r-(r-l)/3;
        if(check2(mid1,x,y)<check2(mid2,x,y)) r=mid2;
        else l=mid1;
    }
    return check2(l,x,y);
}

void solve(){
     
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%lf%lf%lf",x+i,y+i,z+i);
    printf("%.8lf\n",2*min({
     check(x,y),check(x,z),check(y,z)}));
}
int main(){
     
    int _;
    _=1;  
    while(_--){
     
        solve();
    }
    return 0;
}

B Code Names
对可操作的字符串之间建边的话,题意就是选择尽量多的点使得两两之间不相邻,就是最大独立集。一般图的最大独立集不会求,而且原图中一定不会有边为3的环,所以大胆猜测奇环不存在就是二分图。
二分图的最大独立集=总点数-最大匹配数。

//#include 
//#pragma GCC optimize(2)
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define go(i, l, r) for(ll i = (l), i##end = (ll)(r); i <= i##end; ++i)
#define god(i, r, l) for(ll i = (r), i##end = (ll)(l); i >= i##end; --i)
#define ios ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define debug_in  freopen("in.txt","r",stdin)
#define debug_out freopen("out.txt","w",stdout);
#define pb push_back
#define all(x) x.begin(),x.end()
#define fs first
#define sc second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pii;
const ll maxM = 1e6+10;
const ll inf_int = 1e9+10;
const ll inf_ll = 1e17;

void read(int &x){
     
    scanf("%d",&x);
}
void read(ll &x){
     
    scanf("%lld",&x);
}
template<class H, class... T> void read(H& h, T&... t) {
     
    read(h);
    read(t...);
}

void pt(){
      cout<<'\n';}
template<class H, class ... T> void pt(H h,T... t){
      cout<<" "<<h; pt(t...);}

//--------------------------------------------
const int maxn = 1e3+10;
int n, m;
vector<int> G[maxn];
string s[maxn];

int match[maxn];
bool vis[550];
bool find(int a){
     
    for(auto u:G[a]){
     
        if(!vis[u]){
     
            vis[u]=true;
            if(match[u]==0||find(match[u])){
     
                match[u]=a;
                return true;
            }
        }
    }
    return false;
}
void init(){
     
    for(int i = 1;i<=n;i++){
     
        for(int j = i+1;j<=n;j++){
     
            int cnt = 0;
            for(int k = 0;k<s[i].size();k++){
     
                if(s[i][k] == s[j][k]) cnt++;
            }
            if(cnt == s[i].size()-2){
     
                G[i].pb(j); //pt(i,j);
                G[j].pb(i);
            }
        }
    }
}
int main() {
     
    read(n);
    for(int i = 1;i<=n;i++) cin>>s[i];
    init();
    int ans=0;
    for(int i=1;i<=n;i++){
     
        memset(vis,0,sizeof vis);
        if(find(i)){
     
            ans++;
        }
    }
    cout<<n - ans/2<<'\n';
    return 0;
}

C New Maths
a⊗b 就是不进位的乘法
举个栗子:
在这里插入图片描述(加和乘都不进位)
所以 a⊗a的位数就是 a的位数的二倍再减一
所以a最多13位,且乘积的位数只能是奇数。所以爆搜试一试。

#include
using namespace std;
typedef long long ll;
const int N=50;
int n;
char s[N];
int a[N],b[N];
bool check(int k){
     
	int res=0;
	for(int i=0;i<=k;++i) res=(res+b[i]*b[k-i])%10;
	return res==a[k];
}
ll ans=1e18;
void get_max(){
     
	for(int i=n;i<n*2-1;++i)
		if(!check(i)) return ;
	ll res=0,p=1;
	for(int i=0;i<n;++i) res=res+b[i]*p,p*=10;
	ans=min(ans,res);
}
void dfs(int x){
     
	if(x==n){
     
		get_max();
		return ;
	}
	for(int i=0;i<=9;++i){
     
		b[x]=i;
		if(check(x)){
     
			dfs(x+1);
		}
	}
}
void solve(){
     
    scanf("%s",s);
	n=strlen(s);
	if(n%2==0){
     
		puts("-1");
		return ;
	}
	for(int i=0;i<n;++i) a[n-i-1]=s[i]-'0';
	n=(n+1)/2;
	dfs(0);
	cout<<(ans==1e18?-1:ans)<<endl;
}

int main(){
     
	 int _;
    _=1;  
    while(_--){
     
        solve();
    }
    return 0;
}

E Early Orders
我们从前向后依次选择一个数加入序列,当已经选择i个数时,选择下一个数时我们有两个集合分别是:已经选择过的数和未选择过的数。
假设上个数选择的位置是l,那么我们需要找到一个位置r使得未选择的数在r之后全部出现过,那么区间(l,r ]的所有数都是可以选的,不会使接下来选不到某些数,而且为了使得字典序最小,我们需要选择区间内的最小值。
last[i]表示数字i最后出现的位置,那么r 就是未选择集合的最小值,可以对所有的last取最小值,选择一个数之后就将它的last置为inf,线段树即可维护。
那么就剩如何求区间(l,r]的最小值,如果区间有多个最小值时需要选择最左边的哪一个使得 l 尽量小,后续选择范围尽量大以使得字典序更小,那么可以建一个堆来维护,每次选择之前将区间所有值全部添加(因为下一个 r 一定比当前r要大),然后将不属于区间的剔除,选择一个区间的最小值。

//#include 
//#pragma GCC optimize(2)
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define go(i, l, r) for(ll i = (l), i##end = (ll)(r); i <= i##end; ++i)
#define god(i, r, l) for(ll i = (r), i##end = (ll)(l); i >= i##end; --i)
#define ios ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define debug_in  freopen("in.txt","r",stdin)
#define debug_out freopen("out.txt","w",stdout);
#define pb push_back
#define all(x) x.begin(),x.end()
#define fs first
#define sc second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pii;
const ll maxM = 1e6+10;
const ll inf_int = 1e9+10;
const ll inf_ll = 1e17;

void read(int &x){
     
    scanf("%d",&x);
}
void read(ll &x){
     
    scanf("%lld",&x);
}
template<class H, class... T> void read(H& h, T&... t) {
     
    read(h);
    read(t...);
}

void pt(){
      cout<<'\n';}
template<class H, class ... T> void pt(H h,T... t){
      cout<<" "<<h; pt(t...);}

//--------------------------------------------
const int maxn = 2e5+10;
int n,k;
int a[maxn];
struct node2{
     
    int w,id;
    bool operator <(const node2 & o) const{
     
        if(w != o.w) return w > o.w;
        else return id > o.id;
    }
};
bool vis[maxn];
priority_queue<node2> q;
struct node{
     
    int l,r;
    int mi;
}tr[maxn*4];

void pushup(int u){
     
    tr[u].mi = min(tr[u << 1].mi, tr[u << 1 | 1].mi);
}
void build(int u,int l,int r){
     
    tr[u] = {
     l,r};
    if(l == r) return ;
    int mid = l+r>>1;
    build(u<<1,l,mid);
    build(u<<1|1,mid+1,r);
}

void modify(int u,int idx,int v){
     
    if(idx == tr[u].l && idx == tr[u].r) tr[u].mi = v;
    else{
     
        int mid = tr[u].l+tr[u].r>>1;
        if(idx<=mid) modify(u<<1,idx,v);
        else modify(u<<1|1,idx,v);
        pushup(u);
    }
}
int main() {
     

    read(n,k);
    build(1,1,k);
    for(int i = 1;i<=n;i++) {
     
        read(a[i]);
        modify(1,a[i],i);
    }
    int ll = 1;
    vector<int> ans;
	for(int i=1,l=0,r=0;i<=k;++i){
     
		r=tr[1].mi;
		while(l<r) q.push({
     a[l+1],l+1}),l++;
		while(q.size()){
     
			node2 cur = q.top();q.pop();
			if(cur.id < ll || vis[cur.w]) continue;
			else {
     
				ans.pb(cur.w);
				vis[cur.w] = 1;
				modify(1,cur.w,inf_int);
				ll = cur.id+1;
				break;
			}
		}
	}
    for(auto v:ans) printf("%d ",v);
    return 0;
}                      

补:
G Birthday Paradox
m等于总人数。总的情况数就是 36 5 m 365^m 365m,先对n个组分配日期就是 ∏ i = 365 − n + 1 365 i \prod_{i=365-n+1}^{365} i i=365n+1365i ,然后就是将m个人分成输入的组,假设隔板是定的,那么先将m个人全排列就是 m!,再排除组内相同的排列就是
m ! ∏ a [ i ] ! \frac{m!}{\prod a[i]!} a[i]!m! ,然后相同数量的组也是重复的,就是
m ! ( ∏ a [ i ] ! ) ∗ ( ∏ n u m [ j ] ) \frac{m!}{(\prod a[i]!)*(\prod num[j])} (a[i]!)(num[j])m!

#include
using namespace std;
typedef long long ll;
const int N=200100;
int n,a[N];
int sum=0;

double log10(double x){
     
	return log(x)/log(10);
}
double A[40010];
double c(int n,int m){
     
	return A[n]-A[m]-A[n-m];
}
int num[N];
int main(){
                                       
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",a+i),sum+=a[i],num[a[i]]++;
	for(int i=1;i<=40000;++i) A[i]=A[i-1]+log10(i);
	double ans=0;
	for(int i=1;i<=n;++i){
     
		ans=ans+log10(365-i+1)-A[a[i]];
	}
	for(int i=1;i<=sum;++i) ans-=log10(365);
	ans+=A[sum];
	for(int i=1;i<=100;++i)
		if(num[i]) ans-=A[num[i]];
	printf("%.10lf",ans);
}

I 换根dp模板题,记得之前训练联盟好像有一道一样的,可惜没看懂题意,看懂也没时间了。。。

#include
using namespace std;
typedef long long ll;
const int N=200100;
int n,t[N];
ll sum[N],f[N],p[N],d[N],ans[N];
int h[N],e[N],w[N],ne[N],idx;
void add(int a,int b,int c){
     
	e[idx]=b;ne[idx]=h[a];w[idx]=c;h[a]=idx++;
}
ll sz[N];
void dfs(int u,int fa){
     
	sz[u]=1;
	sum[u]=t[u];
	for(int i=h[u];~i;i=ne[i]){
     
		int v=e[i];
		if(v==fa) continue;
		dfs(v,u);
		sz[u]+=sz[v];
		sum[u]+=sum[v];
		d[u]+=d[v]+sz[v]*w[i];
		f[u]+=f[v]+sum[v]*w[i];
	}
}
void dfs1(int u,int fa){
     
	ans[u]=f[u]+t[u]*d[u];
	for(int i=h[u];~i;i=ne[i]){
     
		int v=e[i];
		if(v==fa) continue;
		f[v]=f[v]+(f[u]-f[v]-sum[v]*w[i])+(sum[u]-sum[v])*w[i];
		sum[v]=sum[u];
		d[v]=d[v]+(d[u]-d[v]-sz[v]*w[i])+(n-sz[v])*w[i];
		dfs1(v,u);
	}
}
int main(){
     
	memset(h,-1,sizeof h);
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",t+i);
	for(int i=1;i<n;++i){
     
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		add(a,b,c);add(b,a,c);
	}
	dfs(1,-1);dfs1(1,-1);
	for(int i=1;i<=n;++i) printf("%lld\n",ans[i]);
}

K放弃了,溜了溜了

你可能感兴趣的:(acm)