CFR-843-Div-2解题报告
C. Interesting Sequence
题意:给你
,求最小的 ,使 ,或判断无解。
首先每一位独立,分别考虑。与运算每一位都越来越小,所以
By jiangly
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
i64 n, x;
std::cin >> n >> x;
std::vector<i64> f(60);
for (int i = 0; i < 60; i++) {
if (~n >> i & 1) {
f[i] = n;
} else {
f[i] = (n & ~((1LL << i) - 1)) + (1LL << i);
}
}
i64 m = n;
for (int i = 0; i < 60; i++) {
if (~x >> i & 1) {
m = std::max(m, f[i]);
}
}
for (int i = 0; i < 60; i++) {
if (x >> i & 1) {
if (m >= f[i]) {
std::cout << -1 << "\n";
return;
}
}
}
std::cout << m << "\n";
}
D. Friendly Spiders
题意:有
个点,有点权,两个点之间有边当且仅当这两个点的点权不互质。给定两个点,输出最短路。
两个点的点权不互质等价于有公共的质因数,于是可以考虑质因数分解,并对每个质数建虚点。如果两个点同时连向一个虚点就相当于连边。在此图上跑 01BFS 或 Dijkstra 即可。
By SSRS_
#include <bits/stdc++.h>
using namespace std;
int main(){
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++){
cin >> a[i];
}
int s, t;
cin >> s >> t;
s--;
t--;
int MAX = 0;
for (int i = 0; i < n; i++){
MAX = max(MAX, a[i]);
}
MAX++;
vector<vector<int>> E(n + MAX * 3);
for (int i = 0; i < n; i++){
E[i].push_back(n + a[i]);
}
for (int i = 2; i < MAX; i++){
for (int j = i; j < MAX; j += i){
E[n + j].push_back(n + MAX + i);
E[n + MAX + i].push_back(n + MAX * 2 + j);
}
}
for (int i = 0; i < n; i++){
E[n + MAX * 2 + a[i]].push_back(i);
}
vector<int> d(n + MAX * 3, -1);
d[s] = 0;
vector<int> p(n + MAX * 3, -1);
queue<int> Q;
Q.push(s);
while (!Q.empty()){
int v = Q.front();
Q.pop();
for (int w : E[v]){
if (d[w] == -1){
d[w] = d[v] + 1;
p[w] = v;
Q.push(w);
}
}
}
if (d[t] == -1){
cout << -1 << endl;
} else {
vector<int> ans;
for (int v = t; ; v = p[v]){
if (v < n){
ans.push_back(v);
}
if (v == s){
break;
}
}
reverse(ans.begin(), ans.end());
t = ans.size();
cout << t << endl;
for (int i = 0; i < t; i++){
cout << ans[i] + 1;
if (i < t - 1){
cout << ' ';
}
}
cout << endl;
}
}
E. The Human Equation
题意:有一个数组,每次操作可以选一个子序列,将其所有奇数项
、偶数项 ,或偶数项 、奇数项 。问最少多少次操作能变为全 。 。
做法一
首先变为全零一定可行,因为可以每次只选一位单独加或减。选子序列的操作看起来非常复杂,没法直接操作,于是先找一找性质。
首先可以发现已经为
此时,每次操作一定是全选整个数组(正负交替),进行若干次逼近 set<pair>
或 map<set>
维护每个值在链表上的对应位置,从小到大处理即可。
By cxm1024
#include<bits/stdc++.h>
using namespace std;
#define int long long
int v[600010],lst[600010],nxt[600010],cnt=0;
signed main() {
int t;
cin>>t;
while(t--) {
int n;
cin>>n;
vector<int> a;
for(int i=1;i<=n;i++) {
int x;
cin>>x;
if(x==0) continue;
if(a.empty()||(a.back()>0)!=(x>0)) a.push_back(x);
else a.back()+=x;
}
map<int,set<int> > mp;
int lstt=0;
for(int x:a) {
v[++cnt]=abs(x),lst[cnt]=lstt,nxt[cnt]=cnt+1,lstt=cnt;
mp[abs(x)].insert(cnt);
}
nxt[cnt]=0;
int ans=0;
for(auto &[x,s]:mp) {
ans=max(ans,x);
while(!s.empty()) {
int tmp=*s.begin();
s.erase(s.begin());
if(v[tmp]==0) continue;
v[tmp]=0;
int l=lst[tmp],r=nxt[tmp];
nxt[l]=lst[r]=0;
if(l!=0&&r!=0) {
v[++cnt]=v[l]+v[r]-x;
mp[v[l]].erase(l),mp[v[r]].erase(r);
mp[v[cnt]].insert(cnt);
lst[cnt]=lst[l],nxt[cnt]=nxt[r];
if(lst[cnt]) nxt[lst[cnt]]=cnt;
if(nxt[cnt]) lst[nxt[cnt]]=cnt;
}
}
}
cout<<ans<<endl;
while(cnt) v[cnt]=lst[cnt]=nxt[cnt]=0,cnt--;
}
return 0;
}
做法二
考虑进行操作之后其前缀和数组会怎样变化。如果第一位从
By jiangly
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; i++) {
std::cin >> a[i];
}
std::vector<i64> s(n + 1);
for (int i = 0; i < n; i++) {
s[i + 1] = s[i] + a[i];
}
auto ans = *std::max_element(s.begin(), s.end()) - *std::min_element(s.begin(), s.end());
std::cout << ans << "\n";
}
F. Laboratory on Pluto
题意:在网格中按照网格放单位正方形可以构成一些图形,问在面积为
时的最小周长,以及形成该最小周长的方案数(不考虑旋转,只要正面看不同就不同)。 。
思考可以发现,图案一定趋近于类似正方形的形状(也可能是非常接近正方形的长方形),并从角上去掉多余的格子。对于最小周长,可以从严格正方形附近枚举几个长度取最小值(事实上正方形一定是最小值,附近的长方形可能与其相等)。问题转化为,确定了一些长方形
做法一
考虑如下 DP:
By cxm1024
#include<bits/stdc++.h>
using namespace std;
#define int long long
int f[670][670],s[670][670],g[670],h[670];
int sqt(int x) {
int res=sqrt(x);
while(res*res<x) res++;
while((res-1)*(res-1)>=x) res--;
return res;
}
signed main() {
int t,u,m=998244353;
cin>>t>>u;
if(u==2) cin>>m;
f[0][0]=s[0][0]=1;
for(int j=1;j<=660;j++) s[0][j]=1;
for(int i=1;i<=660;i++) {
for(int j=1;j<=i;j++)
(f[i][j]+=s[i-j][j])%=m;
for(int j=1;j<=660;j++)
s[i][j]=(s[i][j-1]+f[i][j])%m;
}
for(int i=0;i<=660;i++)
for(int j=0;j<=i;j++)
(g[i]+=s[j][660]*s[i-j][660]%m)%=m;
for(int i=0;i<=660;i++)
for(int j=0;j<=i;j++)
(h[i]+=g[j]*g[i-j]%m)%=m;
while(t--) {
int n;
cin>>n;
int tmp=sqt(n),x=tmp+(n+tmp-1)/tmp;
vector<pair<int,int> > v;
for(int i=0;i<=100;i++) {
int p=tmp+i,q=(n+p-1)/p;
if(p+q<x) v.clear(),v.push_back({p,q}),x=p+q;
else if(p+q==x) v.push_back({p,q});
}
if(u==1) {
auto [p,q]=v[0];
cout<<p<<" "<<q<<endl;
for(int i=1;i<=p*q;i++) {
if(i<=n) cout<<"#";
else cout<<".";
if(i%q==0) cout<<endl;
}
continue;
}
int ans=0;
for(auto [p,q]:v)
(ans+=h[p*q-n]*(p!=q?2:1)%m)%=m;
cout<<x*2<<" "<<ans<<endl;
}
return 0;
}
做法二
考虑交换 DP 的两维:
#include<bits/stdc++.h>
using namespace std;
int f[670];
int sqt(int x) {
int res=sqrt(x);
while((res+1)*(res+1)<=x) res++;
while(res*res>x) res--;
return res;
}
signed main() {
int t,u,m;
cin>>t>>u;
if(u==2) {
cin>>m;
f[0]=1;
for(int i=1;i<=660;i++)
for(int x=1;x<=4;x++)
for(int j=i;j<=660;j++)
(f[j]+=f[j-i])%=m;
}
while(t--) {
int n;
cin>>n;
int x=sqt(n),y=(n+x-1)/x;
if(u==1) {
cout<<x<<" "<<y<<endl;
for(int i=1;i<=x*y;i++) {
if(i<=n) cout<<"#";
else cout<<".";
if(i%y==0) cout<<endl;
}
continue;
}
while((x+1)*(y-1)>=n) x++,y--;
int ans=0;
while(1) {
(ans+=f[x*y-n]%m)%=m;
if((x-1)*(y+1)>=n) x--,y++;
else break;
}
cout<<(x+y)*2<<" "<<ans<<endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步