这场好毒瘤,C不特判+不知道哪里写炸导致一直过不去,赛后换了写法才过/kk
然后下分到1600,结果还是不能记分打div3/kk
CF1350 A. Orac and Factors
https://codeforces.com/problemset/problem/1350/A
给出 (nle 10^6,kle 10^9),让 (n) 每次加上自己的最小因数,这样加 (k) 次
- (n) 是偶数,那么每次加的最小因数都是 (2),答案 (n+2k)
- 奇数,它的所有因数肯定都是奇数,那么先枚举出它的最小因数 (x),加上 (x) 就变成了偶数,按照偶数的处理方法再加 (k-1) 次就行,答案 (n+x+2(k-1))
int main(){int T=read();while(T--){
LL n=read(),k=read();
if(n&1){
for(reg int i=3;;i++)if(!(n%i)){
n+=i;break;
}
k--;
}
std::printf("%lld
",n+2*k);
}
return 0;
}
CF1350 B. Orac and Models
https://codeforces.com/problemset/problem/1350/B
给出一列数,要求选其中一些数,符合:
- 排列顺序按照在原数列中的顺序排
- 以上面的排列方式,数大小递增
- 以上面的排列方式,相邻两数在原数列中的下标,前一个数是后一个数的因数
求最多能选几个数
没想到div2B就会出简单的dp
设 (f_i) 为以 (i) 开头,最多能选几个
那么倒着枚举,对于每个 (i),(f_i=max(f_j mid i ext{ 是 }j ext{ 的因数,且} a_j>a_i)+1)
(a) 就是原数列,转移式子比较显然
int a[100006],f[100006];
int main(){int T=read();while(T--){
int n=read();
for(reg int i=1;i<=n;i++) a[i]=read();
int ans=0;
for(reg int i=n;i;i--){
f[i]=0;
for(reg int j=i+i;j<=n;j+=i)
if(a[j]>a[i]) f[i]=std::max(f[i],f[j]);
f[i]++;
ans=std::max(ans,f[i]);
}
std::printf("%d
",ans);
}
return 0;
}
CF1349 A. Orac and LCM
https://codeforces.com/problemset/problem/1349/A
给出数列 (a),求 (gcd({operatorname{lcm}({a_i,a_j}) | i<j}))
就是对于每一对 (a_i,a_j),让它们求一个 (operatorname{lcm}),放到一个新数列里,然后再求这个新数列的 (gcd)
把每个数分解一下,设:
则:
说人话,就是取 (operatorname{lcm}) 的时候就是取质因数质数的较大值,(gcd) 就是取较小值
那么要求的答案:
就是每个指数,都是取每两对数对应的指数,取 (max),再在这些 (max) 里取一个 (min)
那么,对于每一个质因数,我们找出数列中每个数它的指数的最小值和次小值,让答案乘上它的次小值次幂就行了
还要用 (vis) 数组标记一下一个质因数在数列的数中出现了几次,可以看注释
LL a[100005];
int min2[200006],min[200006],vis[200006];
int prime[100005],notprime[200006];
inline void get_prime(int n){
for(reg int i=2;i<=n;i++){
if(notprime[i]) continue;
prime[++prime[0]]=i;
for(reg int j=i+i;j<=n;j+=i) notprime[j]=1;
}
}
int main(){
// std::freopen("tmp.txt","r",stdin);
int n=read();
for(reg int i=1;i<=n;i++) a[i]=read();
if(n==2) return std::printf("%lld",a[1]/std::__gcd(a[1],a[2])*a[2]),0;
std::memset(min,0x7f,sizeof min);std::memset(min2,0x7f,sizeof min2);
LL ans=1;
get_prime(200000);
for(reg int i=1;i<=n;i++){
int num,sqrt=std::sqrt(a[i]);
for(reg int j=1;j<=prime[0];j++){
if(a[i]<prime[j]||sqrt<prime[j]) break;
if(!(a[i]%prime[j])){
num=0;
while(!(a[i]%prime[j])) a[i]/=prime[j],num++;
if(num<min[prime[j]]) min2[prime[j]]=min[prime[j]],min[prime[j]]=num;
else if(num<min2[prime[j]]) min2[prime[j]]=num;
vis[prime[j]]++;
}
}
if(a[i]>1){
if(1<min[a[i]]) min2[a[i]]=min[a[i]],min[a[i]]=1;
else if(1<min2[a[i]]) min2[a[i]]=1;
vis[a[i]]++;
}
}
for(reg int i=2;i<=200000;i++)
if(vis[i]==n) for(reg int j=1;j<=min2[i];j++) ans*=i;
//每个数都包含这个质数,所以用 min2
else if(vis[i]==n-1) for(reg int j=1;j<=min[i];j++) ans*=i;
//有一个数不包含它,不包含它的那个数是 0,所以 min 其实才是第二小的
std::printf("%lld",ans);
return 0;
}
CF1349 B. Orac and Medians
https://codeforces.com/problemset/problem/1349/B
给出一列数 (a),每次可以将 (a) 的一个区间改成这个区间数的中位数,问能不能将数列全都变成 (k)(给定的)
此处,偶数长度序列的中位数,是中间靠左的那个数
如果没有 (k),肯定不行
有 (k),且 (k) 旁边有一个大于等于 (k) 的数,那么可以选这两个数的区间,让它变成两个连续的 (k),然后一个一个扩大区间,最终使得整个序列都变成 (k)
那么考虑怎么让 (k) 旁边出现大于等于 (k) 的数
如果有两个大于等于 (k) 的数相距不超过 (2),也就是中间最多夹一个其他数,那么一定可以
因为如果是这种情况,则一定可以向上面描述的那样,一个一个的扩大区间,使得任意包含这两个数的区间都变成这两个数,那么就可以让 (k) 旁边出现大于等于 (k) 的数
否则一定不行,因为任意一个长度为 (m) 的区间,如果包含 (k),并且想让 (k) 作为它的中位数,则大于等于 (k) 的数至少有 (ceilfrac{m}{2}
ceil) 个
所以如果任意两个大于等于 (k) 的数相距都大于 (2),则在任意长度为 (m) 的区间内,不可能出现 (ceilfrac{m}{2}
ceil) 个大于等于 (k) 的数
所有是个结论题
int a[100005];
int main(){int T=read();while(T--){
int n=read(),k=read(),flag=0;
for(reg int i=1;i<=n;i++){
a[i]=read();
if(a[i]==k) flag=1;
}
a[n+1]=a[n+2]=a[n+3]=0;
if(!flag){
std::puts("no");continue;
}
if(n==1&&a[1]==k) goto YES;
for(reg int i=1;i<=n;i++)if(a[i]>=k){
if(a[i+1]>=k||a[i+2]>=k) goto YES;
}
std::puts("no");continue;
YES:;
std::puts("yes");
}
return 0;
}
CF1349 C. Orac and Game of Life
https://codeforces.com/problemset/problem/1349/C
给出一个 (n imes m) 的格子,每个格子是 (1) 或 (0)。
每次操作,对于每个格子,如果周围有和他一样数字的格子,就改变数字,如果没有,不变
把格子分成两类,第一类是周围有和他一样数字的格子,第二类是没有
- 第一类格子永远是第一类,因为它旁边相同颜色的格子也是第一类,会跟他一起变动,所以它旁边一直有和他数字相同的格子
- 如果第二类旁边有一个第一类,那么第一类会在一次变动后改变颜色,此时,它应该和第二类的这个格子数字相同(因为一开始是不同的),那么,这个第二类就变成了第一类
- 那么第一类的格子每次会将它旁边的格子变成第一类,所以对于一个第二类的格子,它变成第一类所需要的步数,就是和它曼哈顿距离最小的一个第一类格子的曼哈顿距离
所以,我们只要 bfs 出这个所需的步数,然后就是每操作一次,就改变一次,可以用异或得出
int a[1006][1006],type[1006][1006];
int num[1006][1006];
int q[3000006],head,tail,vis[1006][1006];
int n,m;
char s[1006];
const int dx[4]={1,-1,0,0};
const int dy[4]={0,0,1,-1};
inline int no(int x,int y){
if(x<1||y<1||x>n||y>m) return 1;
if(vis[x][y]) return 1;
return 0;
}
inline int check(int i,int j){
if(i-1>0&&a[i][j]==a[i-1][j]) return 1;
if(i+1<=n&&a[i+1][j]==a[i][j]) return 1;
if(j-1>0&&a[i][j-1]==a[i][j]) return 1;
if(j+1<=m&&a[i][j]==a[i][j+1]) return 1;
return 0;
}
inline void bfs(){
reg int x,y,x_,y_,step;
while(tail<=head){
x=q[tail++];y=q[tail++];step=q[tail++]+1;
for(reg int k=0;k<4;k++){
x_=x+dx[k];y_=y+dy[k];
if(no(x_,y_)) continue;
vis[x_][y_]=1;
if(type[x_][y_]==2) num[x_][y_]=step;
q[++head]=x_;q[++head]=y_;q[++head]=step;
}
}
}
int main(){
n=read();m=read();int Q=read();
for(reg int i=1;i<=n;i++){
std::scanf("%s",s+1);
for(reg int j=1;j<=m;j++) a[i][j]=s[j]-48;
}
head=0;tail=1;
for(reg int i=1;i<=n;i++)for(reg int j=1;j<=m;j++){
if(check(i,j)) type[i][j]=1,q[++head]=i,q[++head]=j,q[++head]=0,vis[i][j]=1;
else type[i][j]=2;
}
bfs();
reg int x,y;LL p;
while(Q--){
x=read();y=read();p=read();
if(type[x][y]==1) std::printf("%d
",a[x][y]^(p&1));
else{
if(!num[x][y]) std::printf("%d
",a[x][y]);//永远不会变
else if(p<=num[x][y]) std::printf("%d
",a[x][y]);
else std::printf("%d
",a[x][y]^((p-num[x][y])&1));
}
}
return 0;
}