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);
}
}