A
题意
n*m的矩阵 可以在任意一条边上放灯 灯可以照到边连着的小矩形 问最少需要几盏灯能点亮整个矩阵
题解
实际上推理一下就可以看出来了 每两个小矩形需要一盏灯 如果最后是单个的还需要一盏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
   | #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int main(){     int T;     scanf("%d",&T);     while(T--){         int n,m;         scanf("%d%d",&n,&m);         int ans=n*m/2;         if((n*m)%2){             ++ans;         }         printf("%d\n",ans);     }     return 0; }
   | 
 
B
题意
有n+1个granny 一开始只有一个granny在场地 她可以一次叫任意个granny 但每个granny有自己的人数要求 如果她来的时候人数不达标她就会走 人数包括同时喊来的其他人但不包括她自己 问最多能聚集几个granny
题解
也很简单 按照要求聚集人数来存 然后逐个求sum 如果sum[i]>i那么就说明是能够达到这个数字的 求满足条件的最大的sum[i]
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
   | #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int gran[200020],su[200020]; int main(){     int T;     scanf("%d",&T);     while(T--){         int n;         scanf("%d",&n);         int tmp;         memset(gran,0,sizeof(gran));         memset(su,0,sizeof(su));         gran[0]=su[0]=1;         for(int i=0;i<n;++i){             scanf("%d",&tmp);             ++gran[tmp];         }         int ans=1;         for(int i=1;i<=n;++i){             su[i]=su[i-1]+gran[i];             if(su[i]>i){                 ans=su[i];             }         }         printf("%d\n",ans);     }     return 0; }
   | 
 
C
题意
给一个矩阵 定义方式见题 问从x1,y1到x2,y2的的路径和有多少种可能 只能向下或向右走
题解
给的矩阵很容易看出 向下的值比向右的值大1 也就是一次向下和向右操作的颠倒会差1 推理一下很容易发现 可能的路径和是下限到上限的所有值 下限是一直向右最后向下 上限是一直向下最后向右 再计算一下就能推出差值实际上就是(x2-x1)*(y2-y1) 宽度决定一个差1会积累几次 高度决定积累几个差1 最后答案就是差值+1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int main(){     int T;     scanf("%d",&T);     while(T--){         long long x1,x2,y1,y2;         scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);         long long tmp=(x2-x1)*(y2-y1);         long long res=tmp+1;         printf("%lld\n",res);     }     return 0; }
   | 
 
D
题意
一年n个月 一个月ki天 每天的拥抱值是所在月份的天数 要选连续的x天 问怎么选能让拥抱值最大 可以跨年
题解
跨年问题很好解决 我们计算两年的就可以了 而后我们可以证明 答案的右边界一定是卡着月份结束的 反证法可以推出来 当然做题时候就是靠感觉了 然后只要试每个边界就完了
然而我写的tle了。。用了二分查找依旧tle。。方法写的还是不太好看起来。。
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
   | #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int n; long long month[400020],su[400020]; long long last(int t){     long long tmpindex;     while(tmpindex=(upper_bound(su,su+n+1,t)-su),tmpindex!=(n+1)){         return su[tmpindex]-t;     }     return 0; } long long val(long long start,long long len){     long long res=0,las=0,tmpindex;     while(tmpindex=(upper_bound(su,su+n+1,start)-su),tmpindex!=(n+1)){         if(len==0){             break;         }         int i=tmpindex;         long long tmplen=min(len,su[i]-start);         las=0;         if(i!=0){             las=su[i-1];         }         long long calst=start-las+1;         res+=(calst+calst+tmplen-1)*tmplen/2;         start+=tmplen;         len-=tmplen;     }                                                                      return res; } int main(){     int x;     scanf("%d%d",&n,&x);     for(int i=0;i<n;++i){         scanf("%lld",&month[i]);         month[n+i]=month[i];     }     n=n*2;     su[0]=month[0];     for(int i=0;i<n;++i){         su[i+1]=su[i]+month[i+1];     }     long long ans=val(0,x),start=0,las=x;     long long res=ans;     long long tmp=0;     while(tmp=last(las)){         ans-=val(start,tmp);         ans+=val(las,tmp);         res=max(res,ans);         start+=tmp;         las+=tmp;     }     printf("%lld\n",res);     return 0; }
   |