1. 程式人生 > 實用技巧 >new Date()日期格式處理

new Date()日期格式處理

本來是本著口胡一下的原則去想的,但是最後又調了一個晚上

首先我們有一個很naive的想法,可以列舉每一個質數\(p\),先刪去它的倍數然後在問是否有\(p\)的倍數,就可以用兩次操作判斷出\(p\)是否為\(x\)的倍數了

然後我們粗略一算,\(10^5\)以內的質數有九千多個,直接GG了

但是我們發現這個想法很好,因為涉及到質數的情況很容易按\(\sqrt n\)分開來討論

因此我們考慮先把\(\sqrt n\)內的\(x\)的約數序列\(d_{1\cdots m}\)求出來,然後從\(cur=\prod_{i=1}^m d_i\)開始擴充套件答案

每次嘗試不斷地給\(cur\)乘上\(d_i\)

,然後判斷是否仍為\(x\)的約數即可

由於每個\(d_i\)更新\(cur\)最多隻有$\log $級別的次數,因此可以保證操作次數

但是我們發現此時\(x\)可能還有一個約數是大於\(\sqrt n\)的質數,容易發現當我們刪除完所有的小質數的倍數後,剩下的數恰好是所有的大質數(或者包含\(x\)

因此我們可以去列舉所有大質數\(p\),判斷\(A(p)\)是否等於\(2\)即可(即剩下了\(p\)\(p\times cur\)),答案就是\(p\times cur\)

所以接下來我們就要討論答案就是一個大質數的情況了,由於大質數很多,如果我們還是對於每個數都花上\(2\)次操作去詢問那麼顯然還是GG了

於是陳指導提出了奇妙的閾值做法,具體地,我們設\(S\)表示刪去連續的\(S\)個數之後來檢驗一次答案是否在這\(S\)個數之中

若在的話我們只需要在這\(S\)個數之件掃一遍進行詢問就可以得出答案了

所以我們要最小化\(S+\frac{num}{S}\)\(num\)表示剩下的大質數數量),取\(S=\sqrt {num}\)即可,此時詢問次數\(num+2\sqrt {num}\)

實測可以完美的卡著上限通過此題

#include<cstdio>
#include<iostream>
#include<cmath>
#define RI register int
#define CI const int&
#define A(x) (printf("A %d\n",x),fflush(stdout),scanf("%d",&res),res)
#define B(x) (printf("B %d\n",x),fflush(stdout),scanf("%d",&res),res)
#define C(x) (printf("C %d\n",x),fflush(stdout))
using namespace std;
const int N=100005;
int n,p[N],t[N],tot,res,cnt,cur,ct,S; bool vis[N];
inline void init(CI n)
{
	RI i,j; for (i=2;i<=n;++i)
	{
		if (!vis[i]) p[++cnt]=i;
		for (j=1;j<=cnt&&i*p[j]<=n;++j)
		{
			vis[i*p[j]]=1; if (i%p[j]==0) break;
		}
	}
}
inline int find(CI l,CI r)
{
	for (RI i=l;i<=r;++i) if (A(p[i])) return p[i];
}
int main()
{
	RI i; for (scanf("%d",&n),init(n),i=1;i<=cnt&&p[i]*p[i]<=n;++i)
	if (B(p[i]),A(p[i])) t[++tot]=p[i]; int tp=i; if (tot)
	{
		for (cur=i=1;i<=tot;++i) cur*=t[i];
		for (i=1;i<=tot;++i) while (cur*t[i]<=n&&A(cur*t[i])) cur*=t[i];
		for (i=tp;i<=cnt;++i) if (A(p[i])==2) return C(cur*p[i]),0;
		return C(cur),0;
	}
	for (cur=cnt-i+2,S=sqrt(cur);i<=cnt;++i)
	if (B(p[i]),--cur,++ct==S) { if (A(1)!=cur) return C(find(i-S+1,i)),0; ct=0; }
	return C(A(1)!=1?find(cnt-ct+1,cnt):1),0;
}