Codeforces Round 1028 (Div. 2)(A~C,赛后补D)
赛后看了D的解法,感觉真简单,但是赛时真没想通解法(有想过倒着走的,但是也不很靠近正解),往建边那边想去了
A.Gellyfish and Tricolor Pansy
思路:骑士死了就不能攻击了,所以对于两个人分别和其骑士的血取个min,直接比大小输出答案即可
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<cstring>
#include<math.h>
#include<time.h>
#include<random>
#include<functional>
#include<stack>
#include<unordered_map>
#include<string>
#include<bitset>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
// using namespace __gnu_pbds;
using namespace std;
mt19937 rnd(time(0));
const ll mod = 1e9 + 7;
//const ll p=rnd()%mod;
#define F first
#define S second
// tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update> f;
//find_by_order(k),找第k位(从小到大)的数字,order_of_key(x),x的排名
ll ksm(ll x, ll y)//快速幂
{
ll ans = 1;
x %= mod;
while (y)
{
if (y & 1)
{
ans = ans * x % mod;
}
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
// inline ll read()//快读
// {
// register ll x = 0, f = 1;
// char c = getchar();
// while (c < '0' || c>'9')
// {
// if (c == '-') f = -1;
// c = getchar();
// }
// while (c >= '0' && c <= '9')
// {
// x = (x << 3) + (x << 1) + (c ^ 48); //等价于x*10+c-48,使用位运算加速
// c = getchar();
// }
// return x * f;
// }
ll gcd(ll x, ll y)
{
if (y == 0)return x;
else return gcd(y, x % y);
}
void fio()//加速流
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
struct s
{
ll l, r;
friend bool operator<(const s& a, const s& b)
{
return a.l < b.l;
};
};
ll e1[8] = { 0,1,0,-1,1,1,-1,-1 };
ll e2[8] = { 1,0,-1,0,1,-1,-1,1 };//前面四个为右边开始的逆时针,后面四个为角落
ll zs[2500000];
ll cnt = 0;
void ola(ll x)
{
vector<bool>vis(x + 5);
for (ll i = 2; i <= x; i++)
{
if (!vis[i])zs[++cnt] = i;
for (ll j = 1; i * zs[j] <= x; j++)
{
vis[i * zs[j]] = 1;
if (i % zs[j] == 0)break;
}
}
}
int main()
{
fio();
ll t = 1;
cin>>t;
while(t--)
{
ll a,b,c,d;
cin>>a>>b>>c>>d;
ll l=min(a,c);
ll r=min(b,d);
if(l>=r)cout<<"Gellyfish"<<endl;
else cout<<"Flower"<<endl;
}
return 0;
}
B.Gellyfish and Baby's Breath
思路:注意给的是两个排列,所以可以暴力用set分别维护目前扫过位置的两个排列最大值和其位置实现边遍历边查找,然后根据现有长度算另一个排列的对称点。两个pair中选最优的即可
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<cstring>
#include<math.h>
#include<time.h>
#include<random>
#include<functional>
#include<stack>
#include<unordered_map>
#include<string>
#include<bitset>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
// using namespace __gnu_pbds;
using namespace std;
mt19937 rnd(time(0));
const ll mod =998244353;
//const ll p=rnd()%mod;
#define F first
#define S second
// tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update> f;
//find_by_order(k),找第k位(从小到大)的数字,order_of_key(x),x的排名
ll ksm(ll x, ll y)//快速幂
{
ll ans = 1;
x %= mod;
while (y)
{
if (y & 1)
{
ans = ans * x % mod;
}
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
// inline ll read()//快读
// {
// register ll x = 0, f = 1;
// char c = getchar();
// while (c < '0' || c>'9')
// {
// if (c == '-') f = -1;
// c = getchar();
// }
// while (c >= '0' && c <= '9')
// {
// x = (x << 3) + (x << 1) + (c ^ 48); //等价于x*10+c-48,使用位运算加速
// c = getchar();
// }
// return x * f;
// }
ll gcd(ll x, ll y)
{
if (y == 0)return x;
else return gcd(y, x % y);
}
void fio()//加速流
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
struct s
{
ll l, r;
friend bool operator<(const s& a, const s& b)
{
return a.l < b.l;
};
};
ll e1[8] = { 0,1,0,-1,1,1,-1,-1 };
ll e2[8] = { 1,0,-1,0,1,-1,-1,1 };//前面四个为右边开始的逆时针,后面四个为角落
ll zs[2500000];
ll cnt = 0;
void ola(ll x)
{
vector<bool>vis(x + 5);
for (ll i = 2; i <= x; i++)
{
if (!vis[i])zs[++cnt] = i;
for (ll j = 1; i * zs[j] <= x; j++)
{
vis[i * zs[j]] = 1;
if (i % zs[j] == 0)break;
}
}
}
int main()
{
fio();
ll t = 1;
cin>>t;
while(t--)
{
ll n;
cin>>n;
vector<ll>a(n+4),b(n+4);
for(ll i=1;i<=n;i++)cin>>a[i];
for(ll i=1;i<=n;i++)cin>>b[i];
set<pair<ll,ll>>f1,f2;
for(ll i=1;i<=n;i++){
f1.insert({a[i],i});
f2.insert({b[i],i});
ll l,r;
l=r=0;
auto j=f1.rbegin();
ll x=(*j).first,y=(*j).second;
ll d=i-y+1;
d=b[d];
if(l<x){
l=x,r=d;
}
else if(l<=x){
if(r<=d)r=d;
}
// cout<<l<<" "<<r<<endl;
if(l<r)swap(l,r);
j=f2.rbegin();
x=(*j).first,y=(*j).second;
d=i-y+1;
d=a[d];
if(l<x)l=x,r=d;
else if(l<=x){
if(r<=d)r=d;
}
if(l<r)swap(l,r);
cout<<(ksm(2,l)+ksm(2,r))%mod<<" ";
}
cout<<endl;
}
return 0;
}
C.Gellyfish and Flaming Peony
思路:所有数变成所有数的gcd才是我们的最终目标,所以我们只要算得到这个gcd的最小步数即可(剩余不等于最小公约数的数,我们只需各对其进行一次操作即可),考虑暴力枚举,第一维为选哪个数变,第二维暴力nlogn次去最小化(每次要选最小,这样子对于这个数变成公共gcd的步数就是该数最少的步数)
然后就可以过了,赛时开long longTle了,用int即可稳定过,对了这里的jj溢出了,但却是int型的最大值
(这个是错误解法,被我水过去了,看下面的解法)
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<cstring>
#include<math.h>
#include<time.h>
#include<random>
#include<functional>
#include<stack>
#include<unordered_map>
#include<string>
#include<bitset>
#define ll int
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
// using namespace __gnu_pbds;
using namespace std;
mt19937 rnd(time(0));
const ll mod =998244353;
//const ll p=rnd()%mod;
#define F first
#define S second
// tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update> f;
//find_by_order(k),找第k位(从小到大)的数字,order_of_key(x),x的排名
ll ksm(ll x, ll y)//快速幂
{
ll ans = 1;
x %= mod;
while (y)
{
if (y & 1)
{
ans = ans * x % mod;
}
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
// inline ll read()//快读
// {
// register ll x = 0, f = 1;
// char c = getchar();
// while (c < '0' || c>'9')
// {
// if (c == '-') f = -1;
// c = getchar();
// }
// while (c >= '0' && c <= '9')
// {
// x = (x << 3) + (x << 1) + (c ^ 48); //等价于x*10+c-48,使用位运算加速
// c = getchar();
// }
// return x * f;
// }
ll gcd(ll x, ll y)
{
if (y == 0)return x;
else return gcd(y, x % y);
}
void fio()//加速流
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
struct s
{
ll l, r;
friend bool operator<(const s& a, const s& b)
{
return a.l < b.l;
};
};
ll e1[8] = { 0,1,0,-1,1,1,-1,-1 };
ll e2[8] = { 1,0,-1,0,1,-1,-1,1 };//前面四个为右边开始的逆时针,后面四个为角落
ll zs[2500000];
ll cnt = 0;
void ola(ll x)
{
vector<bool>vis(x + 5);
for (ll i = 2; i <= x; i++)
{
if (!vis[i])zs[++cnt] = i;
for (ll j = 1; i * zs[j] <= x; j++)
{
vis[i * zs[j]] = 1;
if (i % zs[j] == 0)break;
}
}
}
int main()
{
fio();
ll t = 1;
cin>>t;
while(t--)
{
ll n;
cin>>n;
vector<ll>a(n+4);
ll sum=0;
for(ll i=1;i<=n;i++)cin>>a[i],sum=__gcd(sum,a[i]);
ll cnt=1e18;
vector<bool>vis(n+5,0);
for(ll i=1;i<=n;i++){
ll cc=a[i];
ll dd=0;
for(ll j=1;j<=n;j++)vis[j]=0;
vis[i]=1;
while(cc!=sum){
ll jj=1e18;
ll id=0;
for(ll j=1;j<=n;j++){
if(vis[j])continue;
ll u=__gcd(cc,a[j]);
if(jj>u){
jj=u;
id=j;
}
}
vis[id]=1;
dd++;
cc=jj;
}
cnt=min(cnt,dd);
}
ll ans=0;
if(cnt==0){
for(ll j=1;j<=n;j++){
if(a[j]!=sum)ans++;
}
}
else {
ans+=cnt-1;
ans+=n;
}
cout<<ans<<endl;
}
return 0;
}
思路:贪心不行那就是动态规划了呗。所以对于每个可能去dp他的最小次数。dp[x]是变成x的最小步数,把dp[0]设为-1。
第一位枚举a,第二维枚举1~5000,为什么没Tle?实际复杂度为\(n*5000*logn+t*5000\).注意n的总和为5000
正解:
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<cstring>
#include<math.h>
#include<time.h>
#include<random>
#include<functional>
#include<stack>
#include<unordered_map>
#include<string>
#include<bitset>
#define ll int
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
// using namespace __gnu_pbds;
using namespace std;
mt19937 rnd(time(0));
const ll mod =998244353;
//const ll p=rnd()%mod;
#define F first
#define S second
// tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update> f;
//find_by_order(k),找第k位(从小到大)的数字,order_of_key(x),x的排名
ll ksm(ll x, ll y)//快速幂
{
ll ans = 1;
x %= mod;
while (y)
{
if (y & 1)
{
ans = ans * x % mod;
}
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
// inline ll read()//快读
// {
// register ll x = 0, f = 1;
// char c = getchar();
// while (c < '0' || c>'9')
// {
// if (c == '-') f = -1;
// c = getchar();
// }
// while (c >= '0' && c <= '9')
// {
// x = (x << 3) + (x << 1) + (c ^ 48); //等价于x*10+c-48,使用位运算加速
// c = getchar();
// }
// return x * f;
// }
ll gcd(ll x, ll y)
{
if (y == 0)return x;
else return gcd(y, x % y);
}
void fio()//加速流
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
struct s
{
ll l, r;
friend bool operator<(const s& a, const s& b)
{
return a.l < b.l;
};
};
ll e1[8] = { 0,1,0,-1,1,1,-1,-1 };
ll e2[8] = { 1,0,-1,0,1,-1,-1,1 };//前面四个为右边开始的逆时针,后面四个为角落
ll zs[2500000];
ll cnt = 0;
void ola(ll x)
{
vector<bool>vis(x + 5);
for (ll i = 2; i <= x; i++)
{
if (!vis[i])zs[++cnt] = i;
for (ll j = 1; i * zs[j] <= x; j++)
{
vis[i * zs[j]] = 1;
if (i % zs[j] == 0)break;
}
}
}
int main()
{
fio();
ll t = 1;
cin>>t;
while(t--)
{
ll n,m;
cin>>n;
vector<ll>a(n+4);
ll sum=0;
for(ll i=1;i<=n;i++)cin>>a[i],sum=__gcd(sum,a[i]);
sort(a.begin()+1,a.begin()+1+n);
vector<ll>dp(5001,1e9);
dp[0]=-1;
for(ll i=1;i<=n;i++){//n*12
for(ll j=0;j<=5000;j++){
if(dp[j]==1e9)continue;
else {
ll u=__gcd(a[i],j);
dp[u]=min(dp[u],dp[j]+1);
}
}
}
cnt=dp[sum];
ll ans=0;
if(cnt==0){
for(ll j=1;j<=n;j++){
if(a[j]!=sum)ans++;
}
}
else {
ans+=cnt-1;
ans+=n;
}
cout<<ans<<endl;
}
return 0;
}
D.Gellyfish and Camellia Japonica
思路:这道题得逆向思维,显然从最后面开始对我们比较有利,因为最后一个数作为z最后一次出现,在可以得出答案得情况下,其必定等于给出数组中的数,所以首先创建一个数组复制一遍给出的数组k。那么我们思考x和y,显然可以发现x定要大于等于现在的x或z,所以k[x]=max(k[x],k[z]),同理y也是,为什么是这样呢?因为从后往前保证了z的合理性,我们只需保证x和y的合理性,那么取max是我们可以使其变成的最小的数,如果太大了,我们不好调整(因为不能往下调),压着个线,慢慢往上调才比较优,然后再走一遍check一下得出的答案对不对即可。哦对了如果x,y,z中x和y没有一个数等于z,那么再x和y取完max后得设置z的数为0,因为z的值会由x和y确定,后面z的值为0对后面有利(这里设1也行,只要最小即可)(这时候应该不能随机赋值,因为越小越好),最后得出的数组为0的位置不用理即可,因为其代表不会产生影响(如果非要赋值,0~1e9之内都可以,这里说的对象是最后求出来的答案数组哦)。在这之后才check
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<cstring>
#include<math.h>
#include<time.h>
#include<random>
#include<functional>
#include<stack>
#include<unordered_map>
#include<string>
#include<bitset>
#define ll int
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
// using namespace __gnu_pbds;
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
//const ll p=rnd()%mod;
#define F first
#define S second
// tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update> f;
//find_by_order(k),找第k位(从小到大)的数字,order_of_key(x),x的排名
ll ksm(ll x, ll y)//快速幂
{
ll ans = 1;
x %= mod;
while (y)
{
if (y & 1)
{
ans = ans * x % mod;
}
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
// inline ll read()//快读
// {
// register ll x = 0, f = 1;
// char c = getchar();
// while (c < '0' || c>'9')
// {
// if (c == '-') f = -1;
// c = getchar();
// }
// while (c >= '0' && c <= '9')
// {
// x = (x << 3) + (x << 1) + (c ^ 48); //等价于x*10+c-48,使用位运算加速
// c = getchar();
// }
// return x * f;
// }
ll gcd(ll x, ll y)
{
if (y == 0)return x;
else return gcd(y, x % y);
}
void fio()//加速流
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
struct s
{
ll l, r,z;
friend bool operator<(const s& a, const s& b)
{
if(a.l!=b.l)
return a.l < b.l;
return a.r < b.r;
};
};
ll e1[8] = { 0,1,0,-1,1,1,-1,-1 };
ll e2[8] = { 1,0,-1,0,1,-1,-1,1 };//前面四个为右边开始的逆时针,后面四个为角落
ll zs[2500000];
ll cnt = 0;
void ola(ll x)
{
vector<bool>vis(x + 5);
for (ll i = 2; i <= x; i++)
{
if (!vis[i])zs[++cnt] = i;
for (ll j = 1; i * zs[j] <= x; j++)
{
vis[i * zs[j]] = 1;
if (i % zs[j] == 0)break;
}
}
}
int main()
{
fio();
ll t = 1;
cin >> t;
while (t--)
{
ll n, q;
cin >> n >> q;
vector<ll>a(n+4),ans(n+4);
for(ll i=1;i<=n;i++)cin>>a[i],ans[i]=a[i];
vector<s>b(q+5);
for(ll i=1;i<=q;i++){
ll l,r,z;
cin>>l>>r>>z;
b[i]={l,r,z};
}
for(ll i=q;i>=1;i--){
auto [l,r,z]=b[i];
ans[l]=max(ans[z],ans[l]);
ans[r]=max(ans[r],ans[z]);
if(l!=z&&r!=z){
ans[z]=0;
}
}
for(ll i=1;i<=n;i++){
if(ans[i]==0)ans[i]=a[i];
}
vector<ll>k(n+4);
k=ans;
for(ll i=1;i<=q;i++){
auto [l,r,z]=b[i];
k[z]=min(k[l],k[r]);
}
ll flag=0;
for(ll i=1;i<=n;i++){
if(k[i]!=a[i])flag=1;
}
if(flag)cout<<-1<<endl;
else {
for(ll i=1;i<=n;i++)cout<<ans[i]<<" ";
cout<<endl;
}
}
return 0;
}

浙公网安备 33010602011771号