A - Oops, It's Yesterday Twice More
题意
有一个网格,每个网格上有一只袋鼠.求一组移动操作使得它们都移动到给定的点
处,要求移动次数不超过
.
操作用'U'、'D'、'L'、'R'分别表示全体袋鼠向上、向下、向左、向右移动一格,下一步移动会越界的袋鼠不动.
思路
显然只有所有袋鼠都移动到一个角落处才能统一行为.考察点离哪个角落更近(Manhattan距离,即移动的步数最少,若步数相等随便选一个),先将所有袋鼠移动到角落,再从该角落移动到点
.将所有袋鼠移动到一个角落所需的最小步数等于该角落对角的袋鼠移动到该角落的步数,即
步.将所有袋鼠从一个角落移动到点
所需步数为
.似乎加起来
步,超过了最大步数.但是
时,点
离得最近的角落即点
,则只需前
步即可完成.最坏的情况是
为奇数时的网格的中心点
,此时它离各个角落一样远,不妨设都移动到
,则总步数
,满足要求.
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,a,b;
cin>>n>>a>>b;
int d1=abs(a-1)+abs(b-1);
int d2 = abs(a - 1) + abs(b - n);
int d3 = abs(a - n) + abs(b - 1);
int d4 = abs(a - n) + abs(b - n);
int mn=min({d1,d2,d3,d4});
if(mn==d1){
for(int i=1;i<n;i++)cout<<"LU";
for(int i=1;i<a;i++)cout<<"D";
for(int i=1;i<b;i++)cout<<"R";
cout<<"\n";
return 0;
}
else if(mn==d3){
for (int i = 1; i < n; i++)
cout << "DL";
for (int i = 1; i < b; i++)
cout << "R";
for (int i = n; i > a; i--)
cout << "U";
cout << "\n";
return 0;
}
else if(mn==d2){
for (int i = 1; i < n; i++)
cout << "RU";
for (int i = n; i >b; i--)
cout << "L";
for (int i = 1; i < a; i++)
cout << "D";
cout << "\n";
return 0;
}
else if(mn==d4){
for (int i = 1; i < n; i++)
cout << "RD";
for (int i = n; i >b; i--)
cout << "L";
for (int i = n; i > a; i--)
cout << "U";
return 0;
}
return 0;
}
M - Windblume Festival
题意
有组测试数据.每组测试数据有
个数
围成一圈,其中第
个数与第
个数相邻.现进行若干次操作直至只剩下一个数:设当前还剩下
个数,每次操作取定一个
,将令
后删去
,删去后
与
的下一个相邻.求最后剩下的数的最大值.数据保证所有测试数据的
之和不超过
.
特别注意特判的情况
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int a[N];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while(t--){
int n;
cin>>n;
bool flag_n=1,flag_p=1;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]>0) flag_n=0;
if(a[i]<0) flag_p=0;
}
if(n==1){
cout<<a[1]<<'\n';
continue;
}
sort(a+1,a+n+1);
int ans=0;
if(flag_n){
for(int i=1;i<n;i++) ans+=abs(a[i]);
ans+=a[n];
}
else if(flag_p){
for(int i=2;i<=n;i++) ans+=a[i];
ans-=a[1];
}
else{
for(int i=1;i<=n;i++) ans+=abs(a[i]);
}
cout<<ans<<'\n';
}
return 0;
}
C - Klee in Solitary Confinement
题意
给定一个长度为的序列
和一个操作数
.可至多进行一次操作:选定一个区间
,将其中的数
.求最后序列中的众数的出现次数.
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10,offset=2e6;
unordered_set<int> cand;
int freq[N<<2];
vector<vector<int>> mp(N<<2);
int max_subarray_sum(const vector<int>& arr){
int n=arr.size();
int res=arr[0];
int dp0=arr[0],dp1;
for(int i=1;i<n;i++){
dp1=max(dp0+arr[i],arr[i]);
dp0=dp1;
res=max(res,dp1);
}
return max(0,res);
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n,k;
cin>>n>>k;
int ans=0;
for(int i=1;i<=n;i++){
int x;
cin>>x;
mp[x+offset].push_back(i);
cand.insert(x);//插入候选集合
freq[x+offset]++;
ans=max(ans,freq[x+offset]);
}
if(k==0) cout<<ans<<'\n';
else{
for(int x:cand){
vector<int> delta;
vector<int>& v1=mp[x+offset];
vector<int>& v2=mp[x-k+offset];
//类似归并排序
int n1=v1.size(),m1=v2.size();
if(n1==0||m1==0) ans=max(ans,freq[x+offset]);
else{
int i=0,j=0;
while(i<n1&&j<m1){
while(i<n1&&j<m1&&v1[i]<v2[j]){
delta.push_back(-1);
i++;
}
while(i<n1&&j<m1&&v1[i]>v2[j]){
delta.push_back(1);
j++;
}
}
while(i<n1){
delta.push_back(-1);
i++;
}
while(j<m1){
delta.push_back(1);
j++;
}
ans=max(ans,freq[x+offset]+max_subarray_sum(delta));
}
}
cout<<ans<<'\n';
}
return 0;
}
J - Xingqiu's Joke
题意
有组测试数据,每组测试数据输入两相异整数
,每次进行如下三种操作之一,直至
中至少有一个为
,输出最少操作次数.操作:①两数同时
;②两数同时
;③两数同除以它们的一个公共素因子.
思路
在变化中寻找不变量,同时和
让人联想到年龄的增长,注意到年龄差不变,可以发现加减过程中
不变,则每一组
的公共素因子也是
的素因子.可想到对
素因数分解,枚举
的所有素因子
,进行状态
到状态
的转移.显然状态的前两维可只保留一个,不妨设
,则只需保留
,因为最坏的情况要做
次
,从状态
开始记搜.
考虑如何记录状态,最直接的想法是用一个map<pair<int,int>,int>来记数,担心超时可以用哈希表,用一个哈希函数来将每组映射为一个特征值,如
.
考察的状态数.显然第二维的状态数即
的因子个数,由熟知结论:int范围内因数最多的数有
个因子.考察第一维的状态数,即
上下取整共会产生多少个数.注意到int范围内的数至多有
个素因子(即
个
),此时
上取整或下取整分别产生的数的个数约
个,约
个,总共加起来约
个.考察
除以
的顺序不同会不会导致结果数不同,猜测不会,理由在补充部分说明,此处先用约
的时间复杂度玄学过题.
#include <bits/stdc++.h>
#define int long long
using namespace std;
vector<int> pfactor;
struct hash_pair{
template<class T1,class T2>
size_t operator()(const pair<T1,T2>& p)const{
return hash<T1>()(p.first)^hash<T2>()(p.second);
}
};
void divide(int x){
for(int i=2;i<=x/i;i++){
if(x%i==0){
while(x%i==0) x/=i;
pfactor.push_back(i);
}
}
if(x>1) pfactor.push_back(x);
}
unordered_map<pair<int,int>,int,hash_pair> dp;
int dfs(int a,int c){
if(a==1) return 0;
if(c==1) return a-1;
if(dp[make_pair(a,c)]) return dp[make_pair(a,c)];
int res=a-1;
for(int prime:pfactor){
if(c%prime==0){
int rest=a%prime;
int tmp1=rest+1+dfs(a/prime,c/prime);
int tmp2=prime-rest+1+dfs(a/prime+1,c/prime);
res=min({tmp1,tmp2,res});
}
}
return dp[make_pair(a,c)]=res;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while(t--){
int a,b;
cin>>a>>b;
pfactor.clear();
dp.clear();
divide(abs(a-b));
cout<<dfs(min(a,b),abs(a-b))<<'\n';
}
return 0;
}