ARC172 - sol
A - Chocolate
Ms. AtCoder has decided to distribute chocolates to
friends on Valentine's Day. For the -th friend , she wants to give a square chocolate bar of size . She has procured a rectangular chocolate bar of size
. It is partitioned by lines into a grid of rows and columns, each cell being a square. Determine whether it is possible to divide the chocolate bar along the lines into several pieces to obtain all the chocolate bars for her friends. It is fine to have leftover pieces.
。
赛时愣了半天不敢写,感觉非常抽象,小细节错了还交了一发罚时。
感觉首先需要考虑这里的
容易发现,对于一个边长为
具体来说,对于每一个这样的正方形,只要你填进去的面积 小于等于 正方形的面积,你就不需要关心怎么填的问题了,
因为一定有一种方案是可以放下的,这运用到了
于是对于这个
显然正方形越大越好,(因为可以放下更大的方块)。
于是我们以一边为基准,以它的二进制为例不断往下分就可以了,容易发现这样一定更优。
这样的时间复杂度是
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
const int N=1e6+5;
int n,H,W,c[30];
ll S=0;
void calc(int x,ll Sum){
if(!n) return ;
for(int i=x;i>=0;i--){
ll nw=(1ll<<i)*(1ll<<i);
ll tmp=min(1ll*c[i],Sum/nw);
Sum-=1ll*nw*tmp,c[i]-=tmp,n-=tmp;
if(!Sum) break;
}
}
void sol(){
cin>>H>>W>>n;
for(int i=1,x;i<=n;i++) cin>>x,c[x]++,S+=1ll*(1ll<<x)*(1ll<<x);
if(H>W) swap(H,W);
for(int i=29;i>=0;i--){
int len=(1ll<<i),w=W;
if(len<=H){
calc(i,1ll*len*len*(w/len));
w-=1ll*(w/len)*len;
for(int j=i;j>=0;j--)
if(w>=(1ll<<j)) calc(j,1ll*len*(1ll<<j)),w-=(1ll<<j);
H-=len;
}
}
if(!n) cout<<"Yes\n";
else cout<<"No\n";
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
sol();
return 0;
}
B - AtCoder Language
The AtCoder language has
different characters. How many -character strings consisting of characters in the AtCoder language satisfy the following condition? Find the count modulo .
- All
-character subsequences of the string are different. More precisely, there are ways to obtain a -character string by extracting characters from the string and concatenating them without changing the order, and all of these ways must generate different strings. What is
? refers to the total number of ways to choose from items. More precisely, is the value of divided by .
。
场上小丑一样把自己绕到死胡同里面去了。
首先容易发现对于同一个字母,两次相邻的位置中间至少有 于是我们做完了。
现在有两种思路:对于每一个位置的字符,考虑它下一个的位置/考虑转移到它有多少种方案。
如果你选择第二种,你就赢了。
容易发现,对于第一个字符,它有
而对于第二个,它有
发现对于第
所以第
于是就做完了。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
const int N=1e6+5,mod=998244353;
int n,k,l,ans=1;
void sol(){
cin>>n>>k>>l;
if(l<n-k) return cout<<"0",void();
for(int i=1;i<=n;i++){
if(i<=n-k) ans=1ll*ans*(l-i+1)%mod;
else ans=1ll*ans*(l-n+k)%mod;
}
cout<<ans;
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
sol();
return 0;
}
C - Election
This year's AtCoder mayoral election has two candidates, A and B, and
voters have cast their votes. The voters are assigned numbers from to , and voter voted for candidate . Now, the votes will be counted. As each vote is counted, the provisional result will be announced as one of the following three outcomes:
- Result A: Currently, candidate A has more votes.
- Result B: Currently, candidate B has more votes.
- Result C: Currently, candidates A and B have the same number of votes.
There is a rule regarding the order of vote counting: votes from all voters except voter
must be counted in ascending order of their voter numbers. (The vote from voter may be counted at any time.) How many different sequences of provisional results could be announced?
What is a sequence of provisional results?Let
be the result ( A
,B
, orC
) reported when the-th vote is counted. The sequence of provisional results refers to the string .
。
个人认为难度低于 B,你只需要简单分讨即可。
首先,容易发现只有
那么现在我们这样来思考,当
(容易发现,相同的这种情况只会出现在相邻的序列中,指
画一下图分讨一下就可以知道了,只要我们记录一个前缀和,(AB 个数之差),
它的绝对值
#include <bits/stdc++.h>
using namespace std;
int n,sum=0,ans=1;
char c[1000005];
int main(){
scanf("%d%s",&n,c+1);
for(int i=2;i<=n;i++){
if(c[i]!=c[1]&&abs(sum)<=1) ++ans;
sum+=(c[i]=='A'?1:-1);
}
cout<<ans;
return 0;
}
D - Distance Ranking
Place
points in an -dimensional space to satisfy the following conditions: Condition 1 The coordinates of the points consist of integers between
and , inclusive. Condition 2 For
specified as input, must hold. Here, denotes the Euclidean distance between points and . It can be proved that a solution exists under the constraints of the problem. If multiple solutions exist, just print one of them.
What is Euclidean distance? The Euclidean distance between points
and in an -dimensional space, with coordinates for and for , is calculated as .
。
好题!
首先,
容易发现有一种很明显的构造方式:
于是我们尝试把它转化成
(这里我们忽略整数这个条件,因为最后乘上
而由于这个
现在,我们得到的点是:
那么我们再对
于是我们发现影响这个的只是后面的
那么一种构造方式就非常明显了,我们直接让一个为
具体来说,对于第
#include <bits/stdc++.h>
using namespace std;
int n,a[21][21],m;
int main(){
scanf("%d",&n);m=n*(n-1)/2;
for(int i=1;i<=n;i++) a[i][i]=1e8;
for(int i=1,x,y;i<=m;i++) scanf("%d%d",&x,&y),a[x][y]=m-i+1;
for(int i=1;i<=n;i++,puts("")) for(int j=1;j<=n;j++) printf("%d ",a[i][j]);
return 0;
}
E - Last 9 Digits
Determine whether there is a positive integer
such that the remainder of divided by is . If it exists, find the smallest such . You will be given
test cases to solve.
, is neither a multiple of nor a multiple of .
告诉我们要勇于猜结论(在你不会证明的时候)。
首先还是手玩,猜结论:对于每一个
而我们容易发现模数是较大的,所以我们考虑减小模数,从小的模数推过来,同时完成证明。
以下的规律从
首先对于
假设现在的答案是
我们猜测(打表之类的发现)当模数变成
于是就进行一些推式子:(省略
根据二项式定理。
由于后面的每一项都有
,也就是 可以被整除掉。
发现
,这是由于欧拉定理:
,那么 ;(由于 所以对于 是不成立的)
。 而综合这两个条件,一定满足
。
而容易发现这个式子
所以这里的
于是乎,从
而这样推出来之后,每一个数有且仅对应一个也就很容易证明了。
那么代码就是直接模拟即可。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int n,ans=0;
int qpow(int a,int H){
int res=1,b=a;a=a%H;
while(b){if(b&1) res=1ll*res*a%H;a=1ll*a*a%H;b>>=1;}
return res;
}
void sol(){
scanf("%d",&n);
for(int i=1;i<100;i++) if(qpow(i,100)==n%100){ans=i;break;}
for(int i=2,t=100,P=1000;i<9;i++,t*=10,P*=10)
for(int j=0;j<10;j++) if(qpow(ans+j*t,P)==n%P){ans+=j*t;break;}
printf("%d\n",ans);
}
int main(){
int _;scanf("%d",&_);
while(_--) sol();
return 0;
}
F - Walking
The Kingdom of AtCoder has
intersections labeled with numbers from to . Additionally, there are three types of one-way roads in the kingdom:
- Type A: For each
, there is a road from intersection to intersection . - Type B: For each
, there is a road from intersection to intersection . - Type C: For each
, there is a road connecting intersection and intersection with direction . Here,
is X
orY
, where directionX
means the road goes from intersectionto intersection , and direction Y
means it goes from intersectionto intersection . Takahashi wants to walk several times so that for each
, the direction of Type-C road connecting intersections and will be . What is a walk?
Start at any intersection and repeat the following action zero or more times:
- If it is possible to proceed to a Type-C road from the current intersection, walk along the Type-C road to the next intersection.
- Otherwise, if it is possible to proceed to a Type-A or B road from the current intersection, walk along that road to the next intersection.
Then, reverse the directions of all Type-C roads that were passed.
Calculate the minimum number of walks needed to achieve the goal and provide one method to achieve the goal in the minimum number of walks. Under the constraints of this problem, it can be proved that the goal can be achieved in a finite number of walks.
。
跟着提示做到只差一步,那一步还是因为没有退一步,把自己绕进去了。
首先是大量的实验,也就是手玩样例。
我们把计数和偶数分成两排,然后去模拟走的过程就会发现:
对于每一段连续的
略加思考我们发现其实输出答案的其实位置和实际上区间的起始位置是有一定关系的,
所以可以忽略 Walk 这种抽象东西,将每次操作转化到一个序列的区间操作。
和上面说的一样,每次对
那么这个就类似于将两个字符串进行匹配,要么加入一个
分析一下可以知道,记加入为
这样就变成了一个字符串匹配问题,我们可以直接 dp 解决,设
那么转移是非常简单的:
当然会需要满足一些条件,这是简单的。
于是 dp 完之后我们就可以得到答案了,即
实现时再往前面找一次就可以得到那些地方插入,那些地方删除了,
于是直接输出就好了。
注意输出的时候,还会有一些细节,我们从小到大遍历数组,
第
因为当输出第
这样就做完了,时间复杂度
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
const int N=4005;
int n,f[N][N],a[N],b[N],ca=0,cb=0;
string S,T;
int main(){
cin>>n>>S>>T;
memset(f,0x3f,sizeof(f)),f[0][0]=0;
for(int i=0;i<=n;i++)
for(int j=i;j<=n;j++){
if(i>0) f[i][j]=min(f[i][j],f[i-1][j]+1);
if(j>0) f[i][j]=min(f[i][j],f[i][j-1]+1);
if(i>0&&j>0&&S[i-1]==T[j-1]) f[i][j]=min(f[i][j],f[i-1][j-1]+1);
}
printf("%d\n",f[n][n]-n);
int x=n,y=n;
while(x||y){
if(x>0&&f[x][y]==f[x-1][y]+1) --x,a[++ca]=x;
else if(y>0&&f[x][y]==f[x][y-1]+1) --y,b[++cb]=y;
else --x,--y;
}
for(int i=ca;i>0;i--) printf("%d %d\n",2*b[i]+(T[b[i]]=='X'?2:1),2*a[i]+(S[a[i]]=='X'?2:1));
return 0;
}
Conclusion
第一次打 ARC,场上的发挥还是非常烂,我猜结论的水平还有待提高啊。
老是把自己搞到思维的误区里面就出不来了,这一点需要改进,有些时候退一步答案就出来了。
手玩是非常重要的!!!
- 思考时一定要注意有多少种不同的思路,很多时候 计数问题 也有填表法和刷表法两种思路,想不通就退出来换个方向!(B)
- 对于
连接的构造题,我们可以尝试先在 上找到合适的解,再进行微调。(D) - 抽象问题,尝试从手玩中找到规律或者方法。(F)
- 对于模数较大的问题我们可以尝试从小推到大,用类似于归纳法的方法证明结论。(E)
本文作者:H_W_Y
本文链接:https://www.cnblogs.com/H-W-Y/p/18022177/arc172
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步