0.前言
省流:\text{Rk } 1 \to \text{Rk 3},305 \to 255。
T1 虎爷ywk
判断是否存在正整数 n,使得 k|n^2,但 k 不能整除 n,若存在输出最小的 n,否则输出 -1。
1\le k \le 10^{12}
这个数据范围一眼就让我想到 O(\sqrt{k}),但是怎么个根号?有一个显然的想法就是 \sqrt{k} \to k 试除,但是这样显然是不行的。
考虑将 k 质因数分解为 p_{1}^{a_{1}}p_{2}^{a_{2}}p_{3}^{a_{3}}\dots,那么题目构造过程就是当 a_{1} 为偶数时直接除 2 即可,若为奇数则加 1 除 2 即可。这样构造保证最小,最坏情况就是 k|n 直接输出 -1 即可,时间复杂度 O(\sqrt{k})。
#include<bits/stdc++.h>
#define int long long
#define pir pair<int,int>
using namespace std;
int K,fk,ret;
vector<pir> op;
int ksm(int a,int b){
int ret=1;
while(b){
if(b&1) ret=ret*a;
a=a*a;
b>>=1;
}
return ret;
}
signed main(){
freopen("SH.in","r",stdin);
freopen("SH.out","w",stdout);
cin>>K;
fk=K;
for(int i=2;i<=sqrt(fk);i++){
if(K%i==0){
int s=0;
while(K%i==0){
K/=i;
s++;
}
op.push_back(pir(i,s));
}
}
if(K>1) op.push_back(pir(K,1));
ret=1;
for(auto p:op){
if(p.second%2==0) ret*=ksm(p.first,p.second/2);
else ret*=ksm(p.first,(p.second+1)/2);
}
if(ret%fk==0) cout<<-1;
else cout<<ret;
return 0;
}
T2 Johnsonloy的比赛
博弈论,但是 SG 不好做,考虑 DP,最优决策下一定时从大到小拿取,证明考虑反证法与调整法证明即可,所以先排序,让后设 f(i,0/1) 表示到第 i 个题,当前是 Crimson000 学长先手还是 \text{YC乌龙} 学长先手,Crimson000 的最大得分。显然转移:
可以单调队列优化或线段树优化,时间复杂度 O(n \log n)。
#include<bits/stdc++.h>
#define int long long
using namespace std;
constexpr int MN=2e6+15;
int n,a[MN],q[MN],sum[MN],f[MN][2],ql,qr;
struct Segment{
#define ls p<<1
#define rs p<<1|1
struct Node{
int l,r,val;
}t[MN<<2];
void pushup(int p){
t[p].val=max(t[ls].val,t[rs].val);
}
void build(int p,int l,int r){
t[p].l=l;
t[p].r=r;
if(l==r){
t[p].val=-1e9;
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(p);
}
void modify(int p,int pos,int k){
if(t[p].l==t[p].r){
t[p].val=k;
return;
}
int mid=(t[p].l+t[p].r)>>1;
if(mid>=pos) modify(ls,pos,k);
else modify(rs,pos,k);
pushup(p);
}
int query(int p,int fl,int fr){
if(t[p].l>=fl&&t[p].r<=fr){
return t[p].val;
}
int mid=(t[p].l+t[p].r)>>1;
int ret=-1e9;
if(mid>=fl) ret=max(ret,query(ls,fl,fr));
if(mid<fr) ret=max(ret,query(rs,fl,fr));
return ret;
}
}sg;
namespace ly
{
namespace IO
{
#ifndef LOCAL
constexpr auto maxn=1<<20;
char in[maxn],out[maxn],*p1=in,*p2=in,*p3=out;
#define getchar() (p1==p2&&(p2=(p1=in)+fread(in,1,maxn,stdin),p1==p2)?EOF:*p1++)
#define flush() (fwrite(out,1,p3-out,stdout))
#define putchar(x) (p3==out+maxn&&(flush(),p3=out),*p3++=(x))
class Flush{public:~Flush(){flush();}}_;
#endif
namespace usr
{
template<typename type>
inline type read(type &x)
{
x=0;bool flag(0);char ch=getchar();
while(!isdigit(ch)) flag^=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return flag?x=-x:x;
}
template<typename type>
inline void write(type x)
{
x<0?x=-x,putchar('-'):0;
static short Stack[50],top(0);
do Stack[++top]=x%10,x/=10;while(x);
while(top) putchar(Stack[top--]|48);
}
inline char read(char &x){do x=getchar();while(isspace(x));return x;}
inline char write(const char &x){return putchar(x);}
inline void read(char *x){static char ch;read(ch);do *(x++)=ch;while(!isspace(ch=getchar())&&~ch);}
template<typename type>inline void write(type *x){while(*x)putchar(*(x++));}
inline void read(string &x){static char ch;read(ch),x.clear();do x+=ch;while(!isspace(ch=getchar())&&~ch);}
inline void write(const string &x){for(int i=0,len=x.length();i<len;++i)putchar(x[i]);}
template<typename type,typename...T>inline void read(type &x,T&...y){read(x),read(y...);}
template<typename type,typename...T>
inline void write(const type &x,const T&...y){write(x),putchar(' '),write(y...),sizeof...(y)^1?0:putchar('\n');}
template<typename type>
inline void put(const type &x,bool flag=1){write(x),flag?putchar('\n'):putchar(' ');}
}
#ifndef LOCAL
#undef getchar
#undef flush
#undef putchar
#endif
}using namespace IO::usr;
}using namespace ly::IO::usr;
bool cmp(int x,int y){
return x>y;
}
signed main(){
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
read(n);
sg.build(1,1,n);
for(int i=1;i<=n;i++){
read(a[i]);
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
f[1][0]=a[1],f[1][1]=0;
sg.modify(1,1,0);
for(int i=2;i<=n;i++){
f[i][0]=sg.query(1,1,i-1)+sum[i];
f[i][1]=f[i-1][0];
sg.modify(1,i,f[i][1]-sum[i]);
}
put(max(f[n][0],f[n][1]));
return 0;
}
T3 会后空翻的YC乌龙
操作可逆。考虑贪心,每一次遇到 c_{i}\neq s_{i} 的时候我们就开始以 i 为左端点开始枚举右端点,考虑右端点什么取到,当 cnt_{1} \bmod 2 =0 并且 c_{j}=s_{i} 的时候我们可以考虑翻转。
由于翻转操作是可逆的,任何操作序列都可以重新排列为从左到右的贪心操作序列。所以不会漏解,每次操作至少修正一个不匹配的位置,最多 O(n) 次。
#include<bits/stdc++.h>
#define pir pair<int,int>
using namespace std;
constexpr int MN=1e5+15;
int cntc,cnts,n;
string c,s;
vector<pir> op;
int main(){
freopen("YC.in","r",stdin);
freopen("YC.out","w",stdout);
cin>>c>>s;
for(int i=0;i<c.length();i++){
if(c[i]=='0') cntc++;
if(s[i]=='0') cnts++;
}
if(cntc!=cnts){
cout<<"NO";
return 0;
}
for(int i=0;i<c.length();i++){
if(c[i]!=s[i]){
int cnt1=0;
bool flag=0;
for(int j=i;j<c.length();j++){
if(c[j]=='1') cnt1++;
if(!(cnt1&1)&&c[j]==s[i]){
op.push_back(pir(i+1,j+1));
int x=i,y=j;
while(x<y){
swap(c[x],c[y]);
x++,y--;
}
flag=1;
break;
}
}
if(!flag){
cout<<"NO";
return 0;
}
}
}
cout<<"YES\n"<<op.size()<<'\n';
for(auto p:op) cout<<p.first<<" "<<p.second<<'\n';
return 0;
}
T4 博弈论
原:CF1076G
不是我真的服了,pos 开 11 就 RE 敏感肌是吧。
先考虑 [1,n] 怎么做,根据 T2 原则提高组博弈论不考 SG 函数显然考虑 DP,设 f_{i} 表示到第 i 座山,先手能否必赢还是必败。正着 DP 及其难做,考虑倒过来 DP。有两个转移:
- 当 a_{i} 是奇数时,f_{i}=1,先手必胜。
- 当 a_{i} 是偶数时,若 f \in [i+1,i+m] 中没有必败状态则先手必败,否则先手必胜。
奇偶在于看谁跳出去。
时间复杂度 O(nmq) 无法通过。
考虑优化,考虑线段树维护,注意到 m\le 10,考虑从这里下手。根据 f 的性质时 01 序列,考虑把区间有用的 dp 值状压下来。
对于线段树的区间我们记录如果 [r+1,r+m] 的 dp 状态值为 S,那么区间 [l,l+m-1] 的 dp 值是什么,合并很好合并。
考虑区间修改,区间修改其实就是在修改奇偶性,注意到加偶数没有任何卵用,加奇数其实就是区间反转奇偶性,直接打反转 tag 和维护两个状压集合就可以。
进一步优化,许多的 S 是没有用的,我们只需要知道 S 中第一个 0 在哪里就可以了,时间 O(qm \log n)。
恭喜 PPM,成功挂分 100->50!
#include<bits/stdc++.h>
#define int long long
using namespace std;
constexpr int MN=1e6+15;
int n,m,q,a[MN];
struct Segment{
#define ls p<<1
#define rs p<<1|1
struct QWQ{
int pos[16];
//敏感肌pos开小就炸杠
QWQ operator +(const QWQ &x)const{
QWQ ret;
for(int i=1;i<=m+1;i++){
ret.pos[i]=pos[x.pos[i]];
}
return ret;
}
};
struct Node{
int l,r;
int isrev;
QWQ val[2];
}t[MN<<2];
void dorev(int p){
swap(t[p].val[1],t[p].val[0]);
t[p].isrev^=1;
}
void pushdown(int p){
if(t[p].isrev){
dorev(ls);
dorev(rs);
t[p].isrev=0;
}
}
void pushup(int p){
t[p].val[0]=t[ls].val[0]+t[rs].val[0];
t[p].val[1]=t[ls].val[1]+t[rs].val[1];
}
void build(int p,int l,int r){
t[p].l=l;
t[p].r=r;
if(l==r){
if(a[l]==1){
t[p].val[0].pos[m+1]=m+1;
t[p].val[1].pos[m+1]=1;
}else{
t[p].val[0].pos[m+1]=1;
t[p].val[1].pos[m+1]=m+1;
}
for(int i=1;i<=m;i++){
t[p].val[0].pos[i]=t[p].val[1].pos[i]=i+1;
}
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(p);
}
void modify(int p,int fl,int fr){
if(t[p].l>=fl&&t[p].r<=fr){
dorev(p);
return;
}
pushdown(p);
int mid=(t[p].l+t[p].r)>>1;
if(mid>=fl) modify(ls,fl,fr);
if(mid<fr) modify(rs,fl,fr);
pushup(p);
}
QWQ query(int p,int fl,int fr){
if(t[p].l>=fl&&t[p].r<=fr){
return t[p].val[0];
}
pushdown(p);
int mid=(t[p].l+t[p].r)>>1;
if(mid<fl) return query(rs,fl,fr);
if(mid>=fr) return query(ls,fl,fr);
return query(ls,fl,fr)+query(rs,fl,fr);
}
}sg;
namespace ly
{
namespace IO
{
#ifndef LOCAL
constexpr auto maxn=1<<20;
char in[maxn],out[maxn],*p1=in,*p2=in,*p3=out;
#define getchar() (p1==p2&&(p2=(p1=in)+fread(in,1,maxn,stdin),p1==p2)?EOF:*p1++)
#define flush() (fwrite(out,1,p3-out,stdout))
#define putchar(x) (p3==out+maxn&&(flush(),p3=out),*p3++=(x))
class Flush{public:~Flush(){flush();}}_;
#endif
namespace usr
{
template<typename type>
inline type read(type &x)
{
x=0;bool flag(0);char ch=getchar();
while(!isdigit(ch)) flag^=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return flag?x=-x:x;
}
template<typename type>
inline void write(type x)
{
x<0?x=-x,putchar('-'):0;
static short Stack[50],top(0);
do Stack[++top]=x%10,x/=10;while(x);
while(top) putchar(Stack[top--]|48);
}
inline char read(char &x){do x=getchar();while(isspace(x));return x;}
inline char write(const char &x){return putchar(x);}
inline void read(char *x){static char ch;read(ch);do *(x++)=ch;while(!isspace(ch=getchar())&&~ch);}
template<typename type>inline void write(type *x){while(*x)putchar(*(x++));}
inline void read(string &x){static char ch;read(ch),x.clear();do x+=ch;while(!isspace(ch=getchar())&&~ch);}
inline void write(const string &x){for(int i=0,len=x.length();i<len;++i)putchar(x[i]);}
template<typename type,typename...T>inline void read(type &x,T&...y){read(x),read(y...);}
template<typename type,typename...T>
inline void write(const type &x,const T&...y){write(x),putchar(' '),write(y...),sizeof...(y)^1?0:putchar('\n');}
template<typename type>
inline void put(const type &x,bool flag=1){write(x),flag?putchar('\n'):putchar(' ');}
}
#ifndef LOCAL
#undef getchar
#undef flush
#undef putchar
#endif
}using namespace IO::usr;
}using namespace ly::IO::usr;
signed main(){
freopen("boyi.in","r",stdin);
freopen("boyi.out","w",stdout);
read(n,m,q);
for(int i=1;i<=n;i++){
read(a[i]);
a[i]=(a[i]&1)^1;
}
sg.build(1,1,n);
while(q--){
int op,l,r,x;
read(op,l,r);
if(op==1){
read(x);
if(x&1) sg.modify(1,l,r);
}else{
auto ret=sg.query(1,l,r);
if(ret.pos[m+1]==1){
put("Bob");
}else put("Alice");
}
}
return 0;
}
后言
构造太烂了,要加紧学习构造了。
写完题后不要傻坐,赶紧对拍或者检查代码越界,用 fsanitize 越界报错。
成绩不太满意,主要原因还是经验太少和大意,以后一定要更正这些错误。