暑假过半,好想天天睡懒觉…

Hdu 5355 Cake
链接
Cake
题意
有n个大小为{1,2,3…n}的蛋糕,要将这些蛋糕分给m个人,每个人所得蛋糕的大小相等,
且每个完整蛋糕只属于某一个人,即蛋糕不允许切分
分析
n个蛋糕的和sum=n*(n+1)/2,平均数avg=sum/m
因为蛋糕不能切
1.sum%m!=0 即不能整除时,肯定不能平分
2.当avg<n,也不可能平分
3.若有2m个数{1,2,3…2m}肯定可以平分,即连续2m个数肯定可以
4.可以先构造,再dfs
构造:先正向递减构造,再逆向递减构造,这样先构造2*k*m个数
则每个人手上的蛋糕肯定相等,再将剩下的数 {1,2,3…,n-2km}搜索分配
如 n=23,m=3,
第1人:23 18 17 12
第2人:22 19 16 13
第3人:21 20 15 14
剩下{1,2,3…,11} dfs 分配给这三个人
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
   | #include<stdio.h> #include<string.h> #include<vector> using namespace std; const int N=100010; bool vis[N],flag; vector<int> ans[15]; long long n,m,avg,dis,cake[N]; bool dfs(int pos,int sum) {     if(pos>m)         return true;     for(int i=n;i>=1;i--){         if(vis[i])             continue;         if(sum+i==dis){                cake[i]=pos;               vis[i]=true;             if(dfs(pos+1,0))                  return true;             vis[i]=false;             return false;         }         else if(sum+i<dis){               cake[i]=pos;             vis[i]=true;             if(dfs(pos,sum+i))                 return true;             vis[i]=false;         }     }     return false; } int main() {     int T;     scanf("%d",&T);     while(T--){         scanf("%I64d%I64d",&n,&m);         long long sum=n*(n+1)/2;         avg=sum/m;         if(sum%m||avg<n){             printf("NO\n");             continue;         }         printf("YES\n");         int x=n%(2*m);         if(x) x=min(x+2*m,n);         dis=avg;           while(n>x){               dis-=n;             for(int j=1;j<=m;j++)                  ans[j].push_back(n--);             for(int j=m;j>=1;j--)                  ans[j].push_back(n--);             dis-=n+1;         }         memset(vis,0,sizeof(vis));         memset(cake,0,sizeof(cake));         flag=false;         dfs(1,0);         for(int i=1;i<=n;i++)             ans[cake[i]].push_back(i);         for(int i=1;i<=m;i++){             int cnt=ans[i].size();             printf("%d",cnt);             for(int j=0;j<cnt;j++)                 printf(" %d",ans[i][j]);             printf("\n");             ans[i].clear();         }     }     return 0; }
   | 
 
Hdu 5358 First One
链接
First One
题意
给定长度为n的数组
$$ S(i,j) = \sum_{i=1}^{j} a_i $$
$求下列式子的值 ( 默认 \log_2 0 = 0) $
$$ \sum_{i=1}^{n} \sum_{j=i}^{n} (\lfloor \log_2 S(i,j) \rfloor + 1) \times (i + j) $$
分析
$ 若 2^{k-1} \leqslant x \leqslant 2^k ,则 $
$ A = \lfloor \log_2 x \rfloor + 1 = k $
$可以枚举 k,找所有满足 A=k 的区间,并求出对应式子的和$
$找A=k的区间时,可以枚举左区间 i,并找到最小的 l 符合 S(i,l)>=2^{k-1}$
$找到 最大的 r 符合 S(i,r) < 2^k,则 区间 [i,j] (l<=j<=r)的 A=k $
$其贡献值为 k*(i*(r-l+1)+(l+r)*(r-l+1)/2)$
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
   | #include<stdio.h> #include<string.h> const int N=100010; int n; long long bin[40],a[N],sum[N]; void init() {     bin[0]=1;     for(int i=1;i<=35;i++)         bin[i]=bin[i-1]<<1;     bin[0]=0; } long long solve() {     long long ans=0;     for(int k=0;k<=34;k++){         long long L=bin[k],R=bin[k+1];         if(sum[n]<L) break;          int l=1,r=1;         for(int i=1;i<=n;i++){             if(sum[n]-sum[i-1]<L) break;             if(a[i]>=R) continue;             if(l<i) l=i;             if(r<i) r=i;             while(l<=n&&sum[l]-sum[i-1]<L) l++;             while(r<=n&&sum[r]-sum[i-1]<R) r++;             if(l<=r-1){                 long long cnt=r-l;                 ans+=(k+1)*(i*cnt+(l+r-1)*cnt/2);             }         }     }     return ans; } int main() {     int T;     scanf("%d",&T);     init();     while(T--){         scanf("%d",&n);         sum[0]=0;         for(int i=1;i<=n;i++){             scanf("%I64d",&a[i]);             sum[i]=sum[i-1]+a[i];         }         long long ans=solve();         printf("%I64d\n",ans);     }     return 0; }
   | 
 
Hdu 5360 Hiking
链接
Hiking
题意
beta准备邀请他最好的n个朋友 Hiking,
但是 只有当当前同意 Hiking的人数 不小于$ l_i,且不大于 r_i $
第i个朋友才会同意邀请,他会一个一个地邀请好友,
求最多同意Hiking的朋友人数,以及他邀请n个朋友的顺序
分析
贪心思想
先按l从小到大排序,再按r从小到大排序
对于当前满足同意邀请条件的朋友,选择最小的r邀请
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
   | #include<stdio.h> #include<string.h> #include<vector> #include<algorithm> using namespace std; const int N=100010; struct stu{     int l,r,id; }a[N]; int order[N]; bool vis[N]; vector<int> num[N]; vector<int>::iterator it; int cmp(stu x,stu y){     if(x.l!=y.l)         return x.l<y.l;     return x.r<y.r; } int main() {     int T,n;     scanf("%d",&T);     while(T--){         scanf("%d",&n);         for(int i=1;i<=n;i++){             scanf("%d",&a[i].l);             a[i].id=i;         }         for(int i=1;i<=n;i++)             scanf("%d",&a[i].r);         sort(a+1,a+1+n,cmp);         bool flag=true;         int i=1,ans=0;         memset(vis,0,sizeof(vis));         for(int i=0;i<=n;i++)             num[i].clear();         while(flag){             while(i<=n&&ans>=a[i].l){                 num[a[i].r].push_back(a[i].id);                 i++;             }             flag=false;             for(int j=ans;j<=n;j++){                 if(num[j].size()){                     order[ans++]=num[j][0];                     vis[num[j][0]]=true;                     it=num[j].begin();                     num[j].erase(it);                     flag=true;                     break;                 }             }         }         printf("%d\n",ans);         for(i=1;i<=n;i++)             if(!vis[i])                 order[ans++]=i;         for(i=0;i<n-1;i++)             printf("%d ",order[i]);         printf("%d\n",order[n-1]);     }     return 0; }
   | 
 
Hdu 5363 Key Set
链接
Key Set
题意
给定n个数的集合{1,2,…n},求和为偶数的非空子集的个数
分析
大小为n的集合的子集有 $2^n$ 个
和为奇数的子集个数 与和为偶数的子集个数相等
即 和为偶数的子集个数为 $2^{n-1}$,其中有一个为空集
即 和为偶数的非空子集个数为$ 2^{n-1} - 1$
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
   | #include<stdio.h> typedef long long LL; const LL mod=1000000007; LL powMod(LL a,LL b) {     a%=mod;     LL ans=1;     while(b){         if(b&1)             ans=ans*a%mod;         a=a*a%mod;         b>>=1;     }     return ans; } int main() {     int T;     LL n;     scanf("%d",&T);     while(T--){         scanf("%I64d",&n);         printf("%I64d\n",powMod(2,n-1)-1);     }     return 0; }
   |