暑期集训第五场

B. Beautiful Now HDU - 6351

这个题,说的是暴力,但是我想了好久都没有想到怎么判断全排列后符合<=K的情况,在网上看了好多资料,都没有说怎么判断的K,后来好不容易看到一个博主写的,有一个先导知识:使序列有序的最小交换次数。

这个知识就是:利用一个数组把序列里的数的原来的位置用一个数组来记录一下,然后把原序列按照升序排序后,判断两个数组之间有多少个循环节。最少的交换的次数就是数组的长度减去循环节的个数(本质是,一个循环节内如果有n个数,那么最少需要交换n-1次)。

然而在这道题,不能直接把原数组的位置记录之后再全排列,因为一串数里有可能有多个数是一样的,所以我们就利用一个数组来存0->len-1,然后全排列这个排序,把它与已经排列好的数组进行判断算出交换的个数。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
string s;
int k,t,a[10],vis[10],m[10],ta[10];
const ll inf=1e10;
bool cmp(char a,char b){
    return a>b;
}

int main(){
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--){
        memset(a,0,sizeof(a));
        cin>>s>>k;
        int len=s.length();
        for(int i=0,j=0;i<len;i++,j++){
            a[i]=s[j]-'0';
        }

        if(k>=len-1){
            sort(s.begin(),s.end());
            int i=0;
            while(s[i]=='0')i++;
            swap(s[i],s[0]);
            cout<<s<<" ";
            sort(s.begin(),s.end(),cmp);
            cout<<s<<endl;
        }else{
            memset(m,0,sizeof(m));
            for(int i=0;i<len;i++){//the first state
                m[i]=i;
                ta[i]=i;
            }
            ll maxn=-1,minn=inf;

            do{
                memset(vis,0,sizeof(vis));

                if(a[ta[0]]==0)continue;
                int ans=0;
                ll num=0;
                for(int i=0;i<len;i++){
                    if(!vis[i])ans++;

                    int j=i;
                    while(!vis[j]){
                        vis[j]=1;
                        j=m[ta[j]];
                    }
                    num=num*10+a[ta[i]];
                }
           
                if(len-ans<=k){
                    maxn=max(maxn,num);
                    minn=min(minn,num);
                }
            }while(next_permutation(ta,ta+len));
            cout<<minn<<" "<<maxn<<endl;
        }
    }
}

E. Everything Has Changed HDU - 6354

我把余弦定理忘了一干净,自己解了一个线性方程来算出各个角的度数,样例可以过,但是这样解方程要考虑的情况太多了,而且不知道存不存在丢失精度的问题。所以还是用余弦定理好多了,A2+B2-C2+=2ABcosC。

#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
#define pi acos(-1)
const double eps=1e-6;
int t,m;
double R,x,y,r;

int main(){
    cin>>t;
    while(t--){
        cin>>m>>R;
        double ans=2.0*pi*R;
        double tans=ans;
        while(m--){
            cin>>x>>y>>r;
            double D=sqrt(x*x+y*y);
            if(D+r<R||D>=R+r){  
                continue;
            }
            if(fabs(R-r-D)<=(eps)){
                double temp=2.0*pi*r;
                ans+=temp;
                continue;
            }
            double alpha=acos((R*R+D*D-r*r)/(2*R*D));//大圆需要减去的边对应的角的度数
            double beta=acos((r*r+D*D-R*R)/(2*r*D));//小圆的
            double L1=alpha*2*R;
            double L2=beta*2*r;
            ans-=L1;
            ans+=L2;
        }
        printf("%.6lf\n",ans);
    }
}

G. glad you came HDU - 6356

读题都读了好久,解法是用线段树维护区间最小值,然后判断区间最小值是否大于Vi,若是大于了,那就不用往下递归了(其实这样的做法,最坏情况下的时间复杂度应该是O(n2logN),但是他这个数据是随机生成的,所以应该没有卡这个的数据。

#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ll long long
using namespace std;

const int maxn=1e5+10;
const int mod=(1<<30);
unsigned f[15000010];
ll mina[maxn<<2];

int n,m;
unsigned x,y,z;

void pushup(int rt){
    mina[rt]=min(mina[rt<<1],mina[rt<<1|1]);
}

void update(int L,int R,ll v,int l,int r,int rt){
    if(mina[rt]>=v)return;
    if(l==r){
        mina[rt]=v;
        return;
    }
    int m=(l+r)/2;
    if(m>=L)update(L,R,v,lson);
    if(m<R)update(L,R,v,rson);
    pushup(rt);
}

ll query(int L,int R,int l,int r,int rt){
    if(l==r)return mina[rt];
    int m=(l+r)/2;
    ll ans=0;
    if(m>=L)ans=query(L,R,lson);
    if(m<R)ans=query(L,R,rson);
    return ans;
}

unsigned getf(){
    x=x^(x<<11);
    x=x^(x>>4);
    x=x^(x<<5);
    x=x^(x>>14);
    unsigned w=x^(z^y);
    x=y;
    y=z;
    z=w;
    return z;
}

int main(){
    int t;
    cin>>t;
    while(t--){
        memset(mina,0,sizeof(mina));
        scanf("%d%d%d%d%d",&n,&m,&x,&y,&z);
        for(int i=1;i<=3*m;i++){
            f[i]=getf();
        }
        for(int i=1;i<=m;i++){
            ll l=min(f[3*i-2]%n+1,f[3*i-1]%n+1);
            ll r=max(f[3*i-2]%n+1,f[3*i-1]%n+1);
            int w=f[3*i]%mod;
            update(l,r,w,1,n,1);
        }
        ll ans=0;
        for(int i=1;i<=n;i++){
            ll w=query(i,i,1,n,1);
            ans^=(w*i);
        }
        printf("%lld\n",ans);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值