第一次和师兄一起在机房打比赛,听着他们噼里啪啦的键盘声,自己不觉也打得更快了。
rating:1739->1880
f ( n ) 为 n 的 最 小 质 因 数 f(n)为n的最小质因数 f(n)为n的最小质因数,重复t次如下操作:n+=f(n); 输出最终答案
显然 f ( n ) + n f(n)+n f(n)+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,求最长的序列 b 1 , b 2 . . . b k b_1,b_2...b_k b1,b2...bk满足 ∀ i ∈ [ 1 , k ) ∩ N , a [ b i ] < a [ b i 1 ] , a [ b i ] ∣ a [ b i + 1 ] \forall i\in [1,k)\cap \N,a[b_i]∀i∈[1,k)∩N,a[bi]<a[bi1],a[bi]∣a[bi+1].
定义 f [ i ] 表 示 以 i 结 尾 的 最 长 序 列 , 每 次 直 接 枚 举 约 数 即 可 f[i]表示以i结尾的最长序列,每次直接枚举约数即可 f[i]表示以i结尾的最长序列,每次直接枚举约数即可
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;
}
求 gcd { l c m ( a i , a j ) } ( j < i ) \gcd \{lcm(a_i,a_j)\}(jgcd{lcm(ai,aj)}(j<i).
我比赛的时候想到的做法.
l c m ( a i , a j ) = a i a j d = gcd ( a i , a j ) lcm(a_i,a_j)=\dfrac{a_i a_j}{d=\gcd(a_i,a_j)} lcm(ai,aj)=d=gcd(ai,aj)aiaj
对于确定的d,我们再对 满 足 d ∣ a j 的 a j 求 一 遍 gcd 即 可 满足d|a_j的a_j求一遍\gcd即可 满足d∣aj的aj求一遍gcd即可
也就是当我们扫到 j j j的时候,就先钦定它和后面数的gcd(枚举约数).
当扫到 i i i的时候,只需枚举约数 d d d,求一下 a i gcd ( a j ) / d , ( d ∣ a j ) a_i \gcd(a_j)/d,(d|a_j) aigcd(aj)/d,(d∣aj).
复杂度: O ( n m x a [ i ] O(n\sqrt mxa[i] O(nmxa[i]
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;
}
gcd ( l c m ( a 1 , a i ) , l c m ( a 2 , a i ) . . . l c m ( a i − 1 , a i ) ) = l c m ( a i , gcd ( a 1 , . . a i − 1 ) ) \gcd(lcm(a_1,a_i),lcm(a_2,a_i)...lcm(a_{i-1},a_i))=lcm(a_i,\gcd(a_1,..a_{i-1})) gcd(lcm(a1,ai),lcm(a2,ai)...lcm(ai−1,ai))=lcm(ai,gcd(a1,..ai−1))
证明:因为lcm,gcd分别是对质因子的指数取max和min.所以我们只用考虑每个质因子的指数即可.
设对于一个质数 p p p, a [ i ] 的 对 应 的 指 数 为 c i a[i]的对应的指数为c_i a[i]的对应的指数为ci.
则我们需要证明: min { max ( c i , c 1 ) , max ( c i , c 2 ) . . . } = max { c i , min ( c 1 . . c i − 1 ) } \min\{\max(c_i,c_1),\max(c_i,c_2)...\}=\max\{c_i,\min(c_1..c_{i-1})\} min{max(ci,c1),max(ci,c2)...}=max{ci,min(c1..ci−1)}
这个显然是对的,你只需要讨论一下 min ( c 1 . . . c i − 1 ) 与 c i 的 大 小 即 可 \min(c_1...c_{i-1})与c_i的大小即可 min(c1...ci−1)与ci的大小即可
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;
}
对每个质数p考虑贡献,如果我们得到了最小指数和次小指数 t t t,则 a n s = ∏ p t ans=\prod p^t ans=∏pt.
线性筛求A中的f即可.
#include
#include
#include
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);
}
神奇讨论题.
先转换一下
b [ i ] = { 0 a [ i ] < k 1 a [ i ] = k 2 a [ i ] > k b[i]=\begin{cases}0~~ a[i]
然后我们的目标是把全变成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
这种情况.
所以我们 b f s bfs bfs一遍求出每个格子最早被弄如联通块(大小>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;
}
不会,占坑.