前言
第一次和师兄一起在机房打比赛,听着他们噼里啪啦的键盘声,自己不觉也打得更快了。
rating:1739->1880
,重复t次如下操作:n+=f(n); 输出最终答案
显然 一定为偶数,所以后面都是+2.
int n,T,prime[N],tot,f[N];
void get() {
for(int i=2;i<N;i++) {
if(!f[i]) f[i]=i,prime[++tot]=i;
for(int j=1,k;(k=i*prime[j])<N;j++)
if(i%prime[j]) f[k]=prime[j];
else {f[k]=f[i];break;}
}
}
int main() { get();qr(T); while(T--) {
qr(n); ll k; qr(k);
pr2(n+f[n]+(k-1)*2);
}
return 0;
}
貌似埃筛即可,打啥线性筛啊.
给定一个长度为n的数组a,求最长的序列 满足 .
定义
int T,n,ans,a[N],f[N];
int main() {
qr(T); while(T--) {
qr(n); ans=0;
for(int i=1;i<=n;i++) {
qr(a[i]); f[i]=1;
for(int j=1;j*j<=i;j++)
if(i%j==0) {
if(a[i]>a[j]) f[i]=max(f[i],f[j]+1);
if(a[i]>a[i/j]) f[i]=max(f[i],f[i/j]+1);
}
ans=max(ans,f[i]);
}
pr2(ans);
}
return 0;
}
求 .
方法1
我比赛的时候想到的做法.
对于确定的d,我们再对
也就是当我们扫到 的时候,就先钦定它和后面数的gcd(枚举约数).
当扫到 的时候,只需枚举约数 ,求一下 .
复杂度:
ll n,a[N],v[N],ans;
int main() {
qr(n);
for(int i=1;i<=n;i++) {
qr(a[i]);
for(int j=1;j*j<=a[i];j++)
if(a[i]%j==0) {
ans=gcd(ans,a[i]*v[j]);
ans=gcd(ans,a[i]*v[a[i]/j]);
v[j]=gcd(v[j],a[i]/j);
v[a[i]/j]=gcd(v[a[i]/j],j);
}
}
pr2(ans);
return 0;
}
方法2
证明:因为lcm,gcd分别是对质因子的指数取max和min.所以我们只用考虑每个质因子的指数即可.
设对于一个质数 , .
则我们需要证明:
这个显然是对的,你只需要讨论一下
int n;
ll ans,g,x;
int main() {
qr(n);
for(int i=1;i<=n;i++) {
qr(x);
if(i>1) ans=gcd(ans,lcm(g,x));
g=gcd(g,x);
}
pr2(ans);
return 0;
}
方法3
对每个质数p考虑贡献,如果我们得到了最小指数和次小指数 ,则 .
线性筛求A中的f即可.
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 1000010
#define int long long
int n,ans=1;
int prime[maxn],t=0;
bool v[maxn];
void work()
{
for(int i=2;i<=maxn-10;i++)
{
if(!v[i])prime[++t]=i;
for(int j=1;j<=t;j++)
{
if(i*prime[j]>maxn-10)break;
v[i*prime[j]]=true;
if(i%prime[j]==0)break;
}
}
}
int S[maxn],m1[maxn],m2[maxn];
void update(int x,int y)
{
if(y<m1[x])m2[x]=m1[x],m1[x]=y;
else if(y<m2[x])m2[x]=y;
}
void go(int x)
{
for(int i=1;v[x];i++)
if(x%prime[i]==0)
{
int tot=0;S[prime[i]]++;
while(x%prime[i]==0)x/=prime[i],tot++;
update(prime[i],tot);
}
if(x!=1)update(x,1),S[x]++;
}
int ksm(int x,int y)
{
int re=1;
while(y)
{
if(y&1)re*=x;
x*=x;y>>=1;
}
return re;
}
signed main()
{
scanf("%lld",&n);work();
memset(m1,63,sizeof(m1));memset(m2,63,sizeof(m2));
for(int i=1,x;i<=n;i++)scanf("%lld",&x),go(x);
for(int i=1;i<=t;i++)if(S[prime[i]]==n)ans*=ksm(prime[i],m2[prime[i]]);
else if(S[prime[i]]==n-1)ans*=ksm(prime[i],m1[prime[i]]);
printf("%lld",ans);
}
神奇讨论题.
先转换一下
然后我们的目标是把全变成1.
首先无1一定不行.
然后,如果存在{1,1},{1,2},{2,2}都一定能成功.
{1,1}可以无限拓展.
{1,2}可以一步变成{1,1}
{2,2}可以无限拓展,一遇到1就可以生成{1,1}
所以代码特短.
int T,n,k,a[N];
bool pd() {
bool flag=0;
for(int i=1;i<=n;i++) flag|=a[i]==1;
if(!flag) return 0;
if(n==1) return 1;
for(int i=1;i<=n;i++)
if(a[i]&&(a[i+1]||a[i+2])) return 1;
return 0;
}
int main() {
qr(T); while(T--) {
qr(n); qr(k);
for(int i=1;i<=n;i++) {
qr(a[i]);
if(a[i]<k) a[i]=0;
else if(a[i]==k) a[i]=1;
else a[i]=2;
}
a[n+1]=a[n+2]=0;
puts(pd()?"yes":"no");
}
return 0;
}
可以发现联通块可能会越来越少,
除了类似
0101
1010
这种情况.
所以我们 一遍求出每个格子最早被弄如联通块(大小>1)的时间,然后要么一直变要么一直不变.
int n,m,t,d[N][N];
char a[N][N];
const int dx[]={1,-1,0,0},dy[]={0,0,1,-1};
pair<int,int> q[N*N];int l,r;bool vis[N][N];
int main() {
qr(n); qr(m); qr(t);
for(int i=1;i<=n;i++) {
scanf("%s",a[i]+1);
}
l=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) {
bool f=0;
for(int v=0;v<4;v++) {
int tx=i+dx[v],ty=j+dy[v];
if(0<tx&&tx<=n&&0<ty&&ty<=m&&a[i][j]==a[tx][ty]) f=1;
}
if(f) q[++r]=mk(i,j),vis[i][j]=1;
}
while(l<=r) {
int x=q[l].fi,y=q[l].se; l++;
for(int v=0;v<4;v++) {
int tx=x+dx[v],ty=y+dy[v];
if(0<tx&&tx<=n&&0<ty&&ty<=m&&!vis[tx][ty]) {
vis[tx][ty]=1;
q[++r]=mk(tx,ty);
d[tx][ty]=d[x][y]+1;
}
}
}
while(t--) {
ll x,y,z; qr(x); qr(y); qr(z);
if(d[x][y]>=z) putchar(a[x][y]);
else putchar(a[x][y]^((r>0)*(z-d[x][y])&1));
puts("");
}
return 0;
}
不会,占坑.