題意:給出長度爲n的環,從0開始編號到n-1,在這些點上有凹槽可以插硬幣,給出m個硬幣,硬幣位置可以重複,問要使得這些硬幣間的距離相等,輸出一個硬幣所需要移動的最大值.
思路:二分答案,判斷移動mid步是否滿足條件.第1個點可移動的範圍爲[l,r]=[p[0]-mid,p[0]+mid],那麼第2個點可移動的範圍既要滿足與第1個點相差n/m即是在[l+n/m,r+n/m],還要滿足自身的移動範圍[p[1]-mid,p[1]+mid];
所以l=max(l+n/m,p[1]-mid),r=min(r+n/m,p[1]+mid),
若是l>r說明沒有交集,即是不存在同時滿足這兩個條件的移動範圍.
#include<bits/stdc++.h>
using namespace std;
int p[20005],n,m;
bool judge(int d){
int l=p[0]-d,r=p[0]+d;
for (int i=1;i<m;++i){
l=max(l+n/m,p[i]-d);
r=min(r+n/m,p[i]+d);
if(l>r)return 0;
}
return 1;
}
int main(){
int t,k=1;
scanf("%d",&t);
while (t--){
scanf("%d%d",&n,&m);
for (int i=0;i<m;++i){
scanf("%d",p+i);
}
sort(p,p+m);
int left=0,right=n,mid;
while (left<right){
mid=(left+right)/2;
if(judge(mid))right=mid;
else left=mid+1;
}
printf("Case #%d: %d\n",k++,left);
}
}
UVALive6440 - Emergency
Handling
題意:T組數據,每組數據N個事件,P t0,s(t0),r.P表示病人,t0表示其到達時間,s(t0)表示其最開始的嚴重性,r表示嚴重性隨着時間增加的比例,A t,要求輸出在t時刻嚴重性最大的病人嚴重性和他的r.
思路:類似做到過優先隊列的題目.s(t)=s(t0)+r(t-t0)=s(t0)-r*t0+r*t.設x=s(t0)-r*t0,該x是個常數,所以嚴重性和時間是成正比的.因爲比例是0-100的數,所以可以開一個105大的優先隊列數組.
#include<bits/stdc++.h>
using namespace std;
char str[5];
int main(){
int t,n,a,b,c,k=1;
scanf("%d",&t);
while (t--){
priority_queue<int>Q[105];
printf("Case #%d:\n",k++);
scanf("%d",&n);
while (n--){
scanf("%s",str);
if (str[0]=='P'){
scanf("%d%d%d",&a,&b,&c);
Q[c].push(b-a*c);
}
else {
scanf("%d",&a);
int m=0,r=0;
for (int i=0;i<=100;i++){
if (!Q[i].empty()){
if (Q[i].top()+i*a>=m){
m=Q[i].top()+i*a;
r=i;
}
}
}
printf("%d %d\n",m,r);
Q[r].pop();
}
}
}
}
UVALive6434 - Number Assignment
題意:T組數據,每組數據輸入N,M,輸入N個數,輸出分成M組數使得每組數的最大值-最小值之和最小.
思路:分析得到每個數之間的差值越大,就應該分開,總共需要分開M次.
#include<bits/stdc++.h>
using namespace std;
int a[1005],b[1005];
bool cmp(int a,int b){
return a>b; //此處不能寫 a>=b,否則RE.
}
int main(){
int t,m,n,k=1,sum;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=0;i<n;i++){
scanf("%d",a+i);
}
sort(a,a+n);
sum=a[n-1]-a[0];
for(int i=0;i<n-1;i++){
b[i]=a[i+1]-a[i];
}
int cnt=n-1;
sort(b,b+cnt,cmp);
for(int i=0;i<m-1;i++){
sum-=b[i];
}
printf("Case #%d: %d\n",k++,sum);
}
}
題意:看題目Figure1,2就可以明白.
思路:求最小生成樹,將其餘的幾個發電站初始化直接和第一個發電站形成父子關係.
#include<bits/stdc++.h>
using namespace std;
int boss[205];
struct node{
int a,b,c;
}num[40000];
bool cmp(node A,node B){
return A.c<B.c;
}
int find(int x){
return x==boss[x]?x:find(boss[x]);
}
void unio(int x,int y){
int fx=find(x),fy=find(y);
if(fx!=fy)boss[fx]=fy;
}
int main(){
int t,n,m,k,a,b,c,f=1,p1,p;
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++){
boss[i]=i;
}
scanf("%d",&p1);
for(int i=1;i<k;i++){
scanf("%d",&p);
boss[p]=p1;
}
for(int i=0;i<m;i++){
scanf("%d%d%d",&num[i].a,&num[i].b,&num[i].c);
}
sort(num,num+m,cmp);
int ans=0;
for(int i=0;i<m;i++){
if(find(num[i].a)==find(num[i].b))continue;
ans+=num[i].c;
unio(num[i].a,num[i].b);
}
printf("Case #%d: %d\n",f++,ans);
}
}
題意:T組數據,每組數據一個字符串,可以將子字符串用其他字符替換使得其變成一個迴文串,問能形成該回文串的最大長度.題目的樣例解釋很清楚.
思路:模擬一下過程即可.
#include<bits/stdc++.h>
using namespace std;
string str1,str2,str;
int main(){
int t,ans,k=1;
scanf("%d",&t);
while (t--){
cin>>str;
str1=str2="";
ans=0;
int len=str.length();
for (int i=0;i<len/2;++i){
str1=str1+str[i];
str2=str[len-1-i]+str2;
if (str1==str2){
ans+=2;
str1=str2="";
}
}
if (len%2)ans++;
else if (str1!=str2)ans++;
printf("Case #%d: %d\n",k++,ans);
}
}