Codeforces Round 1027 (Div. 3)(A~G,F和G赛后写的)
A. Square Year
思路:首先用sqrtl去判断是否平方,是就输出0和(ll)sqrtl(n),否则输出-1
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#include<functional>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 1e9 + 7;
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
struct s{
ll l,r,id;
friend bool operator<(const s&a,const s&b){
return a.l>b.l;
}
};
int main()
{
fio();
int t=1;
cin >> t;
while (t--)
{
string f;
cin>>f;
ll cnt=0;
for(ll i=0;i<f.size();i++)cnt=cnt*10+f[i]-'0';
ll k=(ll)sqrtl(cnt);
if(k*k==cnt)cout<<0<<" "<<k<<endl;
else cout<<-1<<endl;
}
return 0;
}
B. Not Quite a Palindromic String
思路:很朴素的拆分串做法,串长度为偶数,所以直接先构造出k,用多的构造,随后再试着0,1一起用,如果最后有剩余就输出NO,否则输出YES
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#include<functional>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 1e9 + 7;
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
struct s{
ll l,r,id;
friend bool operator<(const s&a,const s&b){
return a.l>b.l;
}
};
int main()
{
fio();
int t=1;
cin >> t;
while (t--)
{
ll n,k;
cin>>n>>k;
string f;
cin>>f;
ll cn0=0,cn1=0;
for(ll i=0;i<f.size();i++){
if(f[i]=='0')cn0++;
else cn1++;
}
ll flag=0;
while(k>0){
if(cn0>=cn1){
if(cn0>=2)cn0-=2;
else {
flag=1;
break;
}
}
else if(cn1>=2)cn1-=2;
else {
flag=1;
break;
}
k--;
}
while(cn0>0&&cn1>0){
cn0--,cn1--;
}
if(cn0||cn1)flag=1;
if(flag)cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
return 0;
}
C. Need More Arrays
思路:注意数组是非递减的,那么对于同一样的数,其实只要看作一个即可,多的没意义。随后发现要符合数组创建,发现对于去重后的连续段答案为(连续数字长度+1)/2,所以我们把数组划分成多个连续段,然后直接算答案加起来即可。
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#include<functional>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 1e9 + 7;
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
struct s{
ll l,r,id;
friend bool operator<(const s&a,const s&b){
return a.l>b.l;
}
};
int main()
{
fio();
int t=1;
cin >> t;
while (t--)
{
ll n;
cin>>n;
vector<ll>a(n+4);
for(ll i=1;i<=n;i++)cin>>a[i];
ll cnt=0;
ll len=0;
ll ans=0;
for(ll i=1;i<=n;i++){
if(cnt==0)cnt=a[i],len=1;
else if(a[i]==cnt)continue;
else if(a[i]==cnt+1)len++,cnt=a[i];
else {
ans+=(len+1)/2;
len=1;
cnt=a[i];
}
}
ans+=(len+1)/2;
cout<<ans<<endl;
}
return 0;
}
D. Come a Little Closer
思路:不知道删除哪个就枚举所有可能取最小即可,我们可以这样用set<pair<ll,ll>>分别存储行和列的坐标,第一为为数值,第二位为编号。那么特判完n=1后,对于所有可能无非就是移动auto在begin或者rbegin的位置,然后可以算出剩下的坐点构成的矩阵,如果这个矩阵满了,那么我们得长+1或宽+1,两个取个面积min,否则由于有空,我们可以把此时这个点塞进去
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#include<functional>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 1e9 + 7;
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
struct s{
ll l,r,id;
friend bool operator<(const s&a,const s&b){
return a.l>b.l;
}
};
int main()
{
fio();
int t=1;
cin >> t;
while (t--)
{
ll n;
cin>>n;
set<pair<ll,ll>>row,col;
for(ll i=1;i<=n;i++){
ll l,r;
cin>>l>>r;
row.insert({l,i});
col.insert({r,i});
}
if(n==1){
cout<<1<<endl;
continue;
}
ll ans=1e18;
for(ll i=1;i<=n;i++){
auto miy=row.begin();
auto may=row.rbegin();
auto mix=col.begin();
auto max=col.rbegin();
if((*miy).second==i)miy++;
if((*may).second==i)may++;
if((*max).second==i)max++;
if((*mix).second==i)mix++;
ll m1=(*miy).first,m2=(*may).first;
ll c1=(*mix).first,c2=(*max).first;
if((m2-m1+1)*(c2-c1+1)!=n-1){
ans=min(ans,(m2-m1+1)*(c2-c1+1));
}
else {
ans=min(ans,min((m2-m1+2)*(c2-c1+1),(m2-m1+1)*(c2-c1+2)));
}
// cout<<i<<" "<<m<<endl;
}
cout<<ans<<endl;
}
return 0;
}
E. Kirei Attacks the Estate
思路:本质就是维护一个奇性最大连续子序列和偶性最大子序列。所以可以边建树边根据深度设置dp的答案。
d奇数为1否则为0
目前深度为奇性:
\(dp[x][d]=max(dp[x][d]+a[x],dp[fa][d]+a[x]);\)
\(dp[x][d \oplus 1]=max(dp[x][d \oplus 1],dp[fa][d \oplus 1]-a[x]);\)
反之亦然,不会很难
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#include<functional>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 1e9 + 7;
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
struct s{
ll l,r,id;
friend bool operator<(const s&a,const s&b){
return a.l>b.l;
}
};
int main()
{
fio();
int t=1;
cin >> t;
while (t--)
{
ll n;
cin>>n;
vector<ll>a(n+4),g[n+4];
for(ll i=1;i<=n;i++)cin>>a[i];
for(ll i=1;i<n;i++){
ll l,r;
cin>>l>>r;
g[l].push_back(r);
g[r].push_back(l);
}
vector<ll>dep(n+5,0);
vector<vector<ll>>dp(n+5,vector<ll>(2,0));
vector<ll>ans(n+5);
function<void(ll,ll)>dfs=[&](ll x,ll fa){
dep[x]=dep[fa]+1;
ll d=dep[x]%2;
if(d&1){
dp[x][d]=max(a[x],dp[fa][d]+a[x]);
dp[x][d^1]=max(dp[x][d^1],dp[fa][d^1]-a[x]);
}
else {
dp[x][d]=max(a[x],dp[fa][d]+a[x]);
dp[x][d^1]=max(dp[x][d^1],dp[fa][d^1]-a[x]);
}
for(auto j:g[x]){
if(j==fa)continue;
dfs(j,x);
}
ans[x]=dp[x][d];
};
dfs(1,0);
for(ll i=1;i<=n;i++)cout<<ans[i]<<" ";
cout<<endl;
}
return 0;
}
F. Small Operations
思路:
特判x=y和k=1的情况。
对于一个大于2的数,其可以被拆成若干质数的乘积。
那么我们先预处理1~1e6内所有数的质数因数,可重复
随后对于给出的x与y分别遍历存储的vector,如果两个大于k的质因数的乘积不相等就输出-1(操作无法解决它)
然后可以认为操作就是x增加某些质数到个数和y相同,y增加某些质数个数和x相同
所以可以得出两个数,注意数为1,其操作数为0
然后写个函数,对进入函数得进行因数分解,存储到vector,
随后单调枚举(类似\(d*d*d\)的复杂度,实际由于d很小且复杂度远远不到这个三次方这个复杂度)从而得出一个数得最优分配。
把得出的两个数经过函数处理得出的相加即可
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#include<functional>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 1e9 + 7;
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
struct s{
ll l,r,id;
friend bool operator<(const s&a,const s&b){
return a.l>b.l;
}
};
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;
}
}
}
vector<ll>g[1000005];
int main()
{
fio();
int t=1;
cin >> t;
ola(1000000);
for(ll i=1;i<=cnt;i++){
for(ll j=1;j*zs[i]<=1000000;j++){
ll u=j*zs[i];
while(u%zs[i]==0){
g[j*zs[i]].push_back(zs[i]);
u/=zs[i];
}
}
}
while (t--)
{
ll x,y,k;
cin>>x>>y>>k;
ll kk=max(x,y);
vector<ll>vis(kk+2,0),vi(kk+2,0);
if(x==y)cout<<0<<endl;
else if(k==1)cout<<-1<<endl;
else {
ll an1=1,an2=1;
set<ll>f1,f2;
ll k1,k2;
k1=k2=1;
for(auto j:g[x]){
if(j>k)k1*=j;
vis[j]++;
f1.insert(j);
}
for(auto j:g[y]){
if(j>k)k2*=j;
vi[j]++;
f2.insert(j);
}
if(k1!=k2)cout<<-1<<endl;
else {
function<ll(ll)>ck=[&](ll x){
if (x==1)return 0ll;
vector<ll>now;
for (ll i=1;i*i<=x;i++) {
if (x%i==0) {
if (i<=k)
now.push_back(i);
if (x/i!=i&&x/i<=k)now.push_back(x/i);
}
else if (i>k)break;
}
sort(now.begin(),now.end());
// vector<ll>v(x+5,0),bj(x+4,0);
function<ll(ll,ll)>ck1=[&](ll x,ll sz){
if (x==0) {
if (sz==1)return 0ll;
else return (ll)1e18;
}
else {
if (sz==1)return 0ll;
ll d=1e18;
for (ll j=x;j>=0;j--) {
if (sz%now[j]==0) {
d=min(ck1(j,sz/now[j])+1,d);
}
}
return d;
}
};
return ck1((ll)now.size()-1,x);
};
for(auto j:f1){
if(vi[j]<vis[j]){
ll d=vis[j]-vi[j];
while(d--){
an2*=j;
}
}
}
for(auto j:f2){
if(vis[j]<vi[j]){
ll d=vi[j]-vis[j];
while(d--){
an1*=j;
}
}
}
cout<<ck(an1)+ck(an2)<<endl;
}
}
}
return 0;
}
G. Build an Array
思路:首先k==n即可特判。我们可以思考,对于一个两位数的数组,[c,d]我们无非就是先塞了一个数的一系列数然后另一个数的一系列数优,或者先塞一个数的一部分然后再塞另一个数的一部分优。然后我们就会发现第二种的优秀度<=第一种。
不妨设c<d:
如果c是d除2直到d为奇数上的一个过程数字,
第一种:
如果先构c,再构d。那么由于限制,d必定靠近c的数是c*2,其他位置都可以最小,c可以分解到最小;
如果先构d,再构c。那么d可以分解到最小,c可以分解到最小
第二种:
如果写c的一部分再写d的一部分。那么d会受到c的限制而不能全最小分解
如果写d的一部分再写c的一部分,那么c不能最小分解或者d不能最小分解
如果c不是d除2直到d为奇数上的一个过程数字
我先构d再构c仍是优解
所以综上先构d再构c将是优解。
所以答案肯定是先构大数再延申
做个前缀和后缀和求朴素最大
然后枚举所有位置,将其分解到最小,然后加个前面的前缀和后面的后缀,所有可能取个max即可
如果其大于等于k,那么输出YES,否则输出NO
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#include<functional>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 1e9 + 7;
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
struct s{
ll l,r,id;
friend bool operator<(const s&a,const s&b){
return a.l>b.l;
}
};
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;
}
}
}
vector<ll>g[1000005];
int main()
{
fio();
int t=1;
cin >> t;
while (t--)
{
ll n,k;
cin>>n>>k;
vector<ll>a(n+4),b(n+4,0);
for(ll i=1;i<=n;i++)cin>>a[i];
vector<ll>sub(n+4,0),pre(n+4,0);
for(ll i=1;i<=n;i++){
ll u=a[i];
while(u%2==0){
u/=2;
}
b[i]=u;
}
if(n==k)cout<<"YES"<<endl;
else {
vector<ll>now(n+5,0);
a[0]=0,a[n+1]=0;
ll ans=0;
for(ll i=1;i<=n;i++){
ll l=a[i-1];
ll d=a[i];
ll sd=0;
ll flag=0;
while(d){
if(l==d){
flag=sd;
}
if(d&1)break;
d/=2;
sd++;
}
// if(flag){
// l=b[i-1];
// d=a[i];
// sd=0,flag=0;
// while(d){
// if(l==d){
// flag=sd;
// }
// if(d&1)break;
// d/=2;
// sd++;
// }
// }
ans=0;
if(flag==0){
ans+=(1ll<<sd);
}
else {
ans++;
ans+=((1ll<<flag-1)-1)*(a[i]/(1ll<<flag-1)/d);
}
now[i]=ans;
// cout<<ans<<endl;
}
for(ll i=n;i>=1;i--){
sub[i]=sub[i+1]+now[i];
}
for(ll i=n;i>=1;i--){
ll l=a[i+1];
ll d=a[i];
ll sd=0;
ll flag=0;
while(d){
if(l==d){
flag=sd;
}
if(d&1)break;
d/=2;
sd++;
}
// if(flag){
// l=b[i+1];
// d=a[i];
// sd=0,flag=0;
// while(d){
// if(l==d){
// flag=sd;
// }
// if(d&1)break;
// d/=2;
// sd++;
// }
// }
ans=0;
if(flag==0){
ans+=(1ll<<sd);
}
else {
ans++;
ans+=((1ll<<flag-1)-1)*(a[i]/(1ll<<flag-1)/d);
}
now[i]=ans;
}
for(ll i=1;i<=n;i++){
pre[i]=pre[i-1]+now[i];
}
ans=0;
for(ll i=1;i<=n;i++){
ll d=a[i];
ll cs=0;
while(d%2==0){
cs++;
d/=2;
}
ans=max(ans,pre[i-1]+sub[i+1]+(1ll<<cs));
}
// cout<<ans<<endl;
// cout<<pre[n]<<" "<<sub[1]<<endl;
if(ans>=k)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
return 0;
}

浙公网安备 33010602011771号