官方题解:2015 Multi-University Training Contest 6 solutions BY ZJU
1001 Average
HDU 5353:http://acm.hdu.edu.cn/showproblem.php?pid=5353
题意:n个人围成一圈,每对相邻两人可以且最多交换一个糖果,现求一个合法的交换顺序让所有人的糖果数相同(不能则输出NO)
\(1\leqslant n \leqslant 10^5\)
枚举第一人与第二人的三种交换情况。判断哪种能让糖果数相等
其他人若想要全部相等,按照贪心,剩下的交换情况便会固定。
注意全为0时不能交换。所以应把第一人与第二人什么都不做的情况放在最前面
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<string>
#include<map>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define pb push_back
#define LL __int64
#define N 100005
#define INF 1<<30
int op[N];
int a[N];
int b[N];
int main() {
//freopen("C:\\Users\\F\\Desktop\\in.txt", "r", stdin);
//freopen("C:\\Users\\F\\Desktop\\out.txt", "w", stdout);
int T;
int n,m;
LL sum;
scanf("%d",&T);
while(T--) {
sum=0;
scanf("%d",&n);
for(int i=1; i<=n; ++i) {
scanf("%d",&a[i]);
sum+=a[i];
}
if(sum%n!=0) {
printf("NO\n");
continue;
}
LL ave=sum/n;
int flag=0;
for(int i=1; i<=n; ++i) {
a[i]=a[i]-ave;
if(abs(a[i])>2)flag=1;
}
if(flag) {
printf("NO\n");
continue;
}
for(int i=1; i<=3; ++i) {
memcpy(b,a,sizeof(a));
m=0;
if(i==1) op[1]=0; //注意全为0时不能交换
if(i==2) op[1]=1,b[1]--,b[2]++,m=1;
if(i==3) op[1]=-1,b[1]++,b[2]--,m=1;
for(int j=2; j<=n; ++j) {
int next=((j==n)?1:j+1);
if(b[j]==-1) op[j]=-1,b[j]++,b[next]--,m++;
else if(b[j]==1) op[j]=1,b[j]--,b[next]++,m++;
else if(b[j]==0) op[j]=0;
}
flag=0;
for(int j=1; j<=n; ++j) {
if(b[j]!=0) {
flag=1;
break;
}
}
if(!flag)
break;
}
if(flag) {
printf("NO\n");
continue;
}
printf("YES\n");
printf("%d\n",m);
for(int i=1; i<=n; ++i) {
int next=((i==n)?1:i+1);
if(op[i]==-1) printf("%d %d\n",next,i);
if(op[i]==1) printf("%d %d\n",i,next);
}
}
return 0;
}
1003 Cake
HDU 5355:http://acm.hdu.edu.cn/showproblem.php?pid=5355
题意:有n个数1~n,将其分成m组,使每组的和相等
\(1\leqslant n \leqslant 10^5,1\leqslant m \leqslant 10\)
(待修改)
1008 Hiking
HDU 5360:http://acm.hdu.edu.cn/showproblem.php?pid=5360
题意:邀请\(n\)个人去远足,但每个人都有一个条件:在他之前有至少\(l_i\)个人接受邀请,但不超过\(r_i\)个人接受邀请。一个人只要接受了就不能反悔,无论最后的结果是否满足条件。询问一个邀请顺序使最多的人接受邀请。
\(1\leqslant n \leqslant 10^5\)
贪心
先按\(l_i\)升序排列
然后对于当前已接受邀请人数\(cnt\),取满足\(cnt \geqslant l_i\)且\(r_i\)最小的人为下一个邀请目标
可以用优先队列来实现
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<string>
#include<map>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define pb push_back
#define LL __int64
#define N 100005
#define INF 1<<30
struct node{
int l,r,id;
friend bool operator< (node n1, node n2)
{
return n1.r > n2.r;
}
}a[N];
bool cmp(node a,node b){
if(a.l!=b.l)
return a.l<b.l;
return a.r<b.r;
}
int ans[N];
int ansn=1,cnt=0;
priority_queue<node> q;
int vis[N];
int main(){
//freopen("C:\\Users\\F\\Desktop\\in.txt", "r", stdin);
//freopen("C:\\Users\\F\\Desktop\\out.txt", "w", stdout);
int n;
int T;
scanf("%d",&T);
while(T--){
while(!q.empty())q.pop();
memset(vis,0,sizeof(vis));
ansn=1;
cnt=0;
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d",&a[i].l);
for(int i=1;i<=n;++i){
scanf("%d",&a[i].r);
a[i].id=i;
}
sort(a+1,a+n+1,cmp);
if(a[1].l==0)
q.push(a[1]);
int k=2;
node now;
while(!q.empty()){
now=q.top();
while(!(cnt>=now.l&&cnt<=now.r)&&(!q.empty())){
q.pop();
if(!q.empty())
now=q.top();
}
if(!q.empty()){
ans[ansn++]=now.id;
q.pop();
cnt++;
}
while(cnt>=a[k].l&&k<=n)
q.push(a[k++]);
}
printf("%d\n",cnt);
int first=1;
for(int i=1;i<=ansn-1;++i){
if(!first)printf(" ");
printf("%d",ans[i]);
vis[ans[i]]=1;
first=0;
}
for(int i=1;i<=n;++i){
if(!vis[i]){
if(!first)printf(" ");
printf("%d",i);
first=0;
}
}
printf("\n");
}
return 0;
}
1011 Key Set
HDU 5363:http://acm.hdu.edu.cn/showproblem.php?pid=5363
题意:一个集合S包含n个数1~n,当一个集合里数的和为偶数时这个集合被称作Key Set,现在问集合S有多少个非空子集是Key Set
\(1\leqslant n \leqslant 10^9\)
通过观察数据可以得出通项公式\(a_n=2^n-1\)
用快速幂便可得出答案
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<string>
#include<map>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define pb push_back
#define LL __int64
#define N 100005
#define INF 1<<30
#define MOD 1000000007
LL pm(LL a,LL b)
{
LL ret=1;
while(b){
if(b&1) ret=ret*a%MOD;
a=a*a%MOD;
b=b>>1;
}
return ret;
}
int main()
{
int T,n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
LL ans=(pm(2,n-1)-1+MOD)%MOD;
printf("%I64d\n",ans);
}
return 0;
}
(待续。。。)