正睿多校联盟训练Week6
并没有参加
Problem A.阿瓦分蛋糕
输入文件: cake.in
输出文件: cake.out
时间限制: 1 second
空间限制: 512 megabytes
阿瓦为了庆祝自己自己成长为了一只可爱的小猫,决定提前过生日!
她觉得,在这一年当中帮助过他最多的就是阿卡和烤乐滋了,于是决定这次只请阿卡和烤乐滋两个人吃蛋糕。
阿瓦买了一个 n × m 的蛋糕,她打算分给三个人吃,同时她切蛋糕的时候为了美观,只会在整块的蛋糕上一
划到底。也就是说,她如果在蛋糕上切了一刀,那么这一刀的起点和终点一定在蛋糕的边界上。同时这一刀切下去
的痕迹一定是平行于蛋糕的某条边界的线段,阿瓦认为这样才比较整齐。很容易看出,这样一来阿瓦一定会将整个
蛋糕分成三个长方形。另外值得注意的是,当你切完了一刀之后,蛋糕自动一分为二,你的下一刀的起点或终点就
可以在新产生的边界上了。
阿瓦希望分给三个人的蛋糕面积尽量平均,也就是三个人当中,分到的最大面积与最小面积之差最小。她希望
你来替她求出那个最小的面积差。
Input
一行两个数 n- m。意义如题面中所述。
Output
一行一个数,表示最大面积与最小面积之差。
Example
cake.in | cake.out |
3 3 | 0 |
Constraints
对于 30% 的数据, n, m ≤ 10。
对于 70% 的数据, n, m ≤ 3000 。
对于 100% 的数据, n, m ≤ 1e5。
看一看这道题应该是乱搞。“有一万种方法能过O(1)。"
当然如果蛋糕面积为3的倍数,直接输出0。
题解里给出了一种“O(n)”的做法,即枚举第一次切得位置,那么第二次一定是均分。
然而写完发现理解题意错了。30分。
事实上蛋糕的这个矩形本身就被分成了有限个1x1的小矩形。我们只能从“这种边界”来进行切割。
枚举两次。纵着切和横着切。如果只枚举一次,那么70分。
在各自枚举纵着切和横着切的时候还要枚举第二刀是顺着第一刀的方向切还是垂直第一刀方向切。QAQ。
考虑全面,就不是难题了。QAQ。注意开long long。
code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 ll n,m; 5 ll maxer,miner; 6 ll a,b,c; 7 ll ans=0x7f7f7f7f; 8 int main() 9 { 10 scanf("%lld%lld",&n,&m); 11 if(n*m%3==0) 12 { 13 printf("0\n"); 14 return 0; 15 } 16 for(ll i=1;i<=n;i++) 17 { 18 a=(n-i)*m; 19 b=(i>>1)*m; 20 c=i*m-b; 21 maxer=max(max(a,b),c); 22 miner=min(min(a,b),c); 23 ans=min(ans,maxer-miner); 24 b=(m>>1)*i; 25 c=i*m-b; 26 maxer=max(max(a,b),c); 27 miner=min(min(a,b),c); 28 ans=min(ans,maxer-miner); 29 } 30 for(ll i=1;i<=m;i++) 31 { 32 a=(m-i)*n; 33 b=(i>>1)*n; 34 c=i*n-b; 35 maxer=max(max(a,b),c); 36 miner=min(min(a,b),c); 37 ans=min(ans,maxer-miner); 38 b=(n>>1)*i; 39 c=i*n-b; 40 maxer=max(max(a,b),c); 41 miner=min(min(a,b),c); 42 ans=min(ans,maxer-miner); 43 } 44 printf("%lld",ans); 45 return 0; 46 }
Problem B.幻想机器人
输入文件: robot.in
输出文件: robot.out
时间限制: 1 second
空间限制: 512 megabytes
幻想世界科技中心研发出了一种机器人,这种机器人的主要作用是清扫地面。但由于性能还不够稳定,所以它
正常工作的时间不是连续的。
更具体地说,我们可以把幻想世界的地面抽象成一个 n 行 m 列的网格,这个机器人刚开始在科技中心的位置
(x, y),即第 x 行第 y 列,我们把左上角定为第一行第一列。初始时整个网格除了科技中心的位置都是未清扫过的,
科技中心由于测试了多遍机器人的功能非常洁净不需要清扫。
接下来,人们可以给机器人下达一系列命令,但每个命令都是L(左)R(右)U(上)D(下)之
一。表示让机器人往指定的方向移动一格。如果当前格子还能够朝指定方向移动一格,则移动,如果在指定方向已
到达边界,则不移动,并输出一行"AWaDa!"(不包含引号)。
机器人性能不够稳定,它每 K 个指令后清扫一遍它所在的格子。也就是说,第 K、 2K、 3K 个指令后它所
在的格子都会被清扫一遍。注意,不移动位置的指令也算作一个指令。另外,每清扫到一个之前清扫过的格子,输
出一行"AKTang!"(不包含引号)。
最后,大家最关心的还是地面被清扫得怎么样,请你最后再输出一个数,表示未被清扫过的地面格子数。
Input
第一行六个数 n-m- K- len- x- y。意义如题面中所述。 len 表示指令的长度。
第二行一个长度为 len 的字符串,每个字符都是L,R,U,D之一,依次表示每个指令。
Output
对于无法移动的情况,输出一行"AWaDa!"。对于清扫过重复格子的情况,输出一行"AKTang!"。最后输出一行
一个数表示未被清扫过的格子数。
注意输出要按照时间顺序输出。
乍一看还以为是dfs,其实是水模拟。但是很难满分啊QAQ。
读题,明确:题目有两种操作,移动,清扫。清扫仅在第k,2k...步操作后进行。(开始读题这理解错了QAQ。
另外,数据有点不友好,我们没法开到1e9的数组来记录有没有被清扫过。还好我们有伟大的stl!
这里用到了map,建立一个矩阵中第几个格(longlong) 到这个格是否走过的映射。
一个矩阵中第几个格用坐标如何表示可以现场用坐标模拟一下。QAQ。
细节:起点肯定是被扫过的,起点的map设为1。但是起点也不一定是1啊,开始写成cnt[1]=1...
代码中mul()函数是64位大整数乘法,亲测用不用时间差别不大。QAQ。
code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<map> 5 6 using namespace std; 7 8 typedef long long ll; 9 int len; 10 ll n,m,k,x,y,fin; 11 map<ll,bool> cnt; 12 13 ll mul(ll a,ll b) 14 { 15 ll ans=0; 16 while(b) 17 { 18 if(b&1) ans=ans+a; 19 b>>=1; 20 a=a*2; 21 } 22 return ans; 23 } 24 25 int main() 26 { 27 scanf("%lld%lld%lld%d%lld%lld",&n,&m,&k,&len,&x,&y); 28 char ch=getchar();cnt[m*(x-1)+y]=1;//不要想成特殊,一般化 QAQ 29 for(ll i=1;i<=len;i++) 30 {//移动和清扫是不一样的 QAQ 明确操作 31 scanf("%c",&ch); 32 if(ch=='U') 33 { 34 if(x==1) printf("AWaDa!\n"); 35 else x--; 36 } 37 if(ch=='L') 38 { 39 if(y==1) printf("AWaDa!\n"); 40 else y--; 41 } 42 if(ch=='R') 43 { 44 if(y==m) printf("AWaDa!\n"); 45 else y++; 46 } 47 if(ch=='D') 48 { 49 if(x==n) printf("AWaDa!\n"); 50 else x++; 51 } 52 if(i%k==0) 53 { 54 if(cnt[m*(x-1)+y]) printf("AKTang!\n"); 55 else cnt[m*(x-1)+y]=1,fin++; 56 } 57 } 58 printf("%lld\n",mul(m,n)-fin-1); 59 //用不用mul()差别不大 QAQ 60 return 0; 61 }
可以用并查集求出联通块个数。最后答案就是m^联通块个数(根据加法原理)。
并查集+快速幂
code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 typedef long long ll; 5 int n,m,T; 6 ll ans; 7 ll moder=998244353; 8 int fa[200000]; 9 10 int getf(int p) 11 { 12 if(fa[p]==p) return p; 13 else 14 { 15 fa[p]=getf(fa[p]); 16 return fa[p]; 17 } 18 } 19 20 void merge(int p,int q) 21 { 22 int pp=getf(p); 23 int qq=getf(q); 24 if(qq!=pp) fa[qq]=pp; 25 } 26 27 ll ksm(ll a,ll b) 28 { 29 ll tot=1; 30 while(b) 31 { 32 if(b&1) tot=tot*a%moder; 33 b>>=1; 34 a=a*a%moder; 35 } 36 return tot%moder; 37 } 38 39 int main() 40 { 41 scanf("%d%d%d",&n,&m,&T); 42 for(int i=1;i<=n;i++) fa[i]=i; 43 for(int i=1;i<=T;i++) 44 { 45 int x=0,y=0; 46 scanf("%d%d",&x,&y); 47 merge(x,y); 48 } 49 for(int i=1;i<=n;i++) if(fa[i]==i) ans++; 50 printf("%lld",ksm(m,ans)); 51 return 0; 52 }
直接上sol好了...另外不能分1,1肯定是没有贡献的。
这题还得打个高精。难受。
code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int T; 5 ll R; 6 int ans[3000],now[3000]; 7 void mul(int x) 8 { 9 memset(now,0,sizeof(now)); 10 for(int i=1;i<=ans[0];i++) 11 { 12 now[i]+=ans[i]*x%10; 13 now[i+1]+=ans[i]*x/10; 14 now[i+1]+=now[i]/10; 15 now[i]%=10; 16 } 17 for(int i=1;i<=ans[0];i++) 18 ans[i]=now[i]; 19 if(now[ans[0]+1]) 20 { 21 ans[0]++; 22 ans[ans[0]]=now[ans[0]]; 23 } 24 } 25 int main() 26 { 27 scanf("%d",&T); 28 for(int i=1;i<=T;i++) 29 { 30 scanf("%lld",&R); 31 ans[0]=ans[1]=1; 32 int tmp=R/3; 33 if(R%3==0) 34 { 35 for(int j=1;j<=tmp;j++) 36 mul(3); 37 } 38 if(R%3==1) 39 { 40 for(int j=1;j<=tmp-1;j++) 41 mul(3); 42 mul(4); 43 } 44 if(R%3==2) 45 { 46 for(int j=1;j<=tmp;j++) 47 mul(3); 48 mul(2); 49 } 50 for(int i=ans[0];i>=1;i--) 51 printf("%d",ans[i]); 52 printf("\n"); 53 memset(ans,0,sizeof(ans)); 54 } 55 return 0; 56 }