20210807 noip32
考场
开题,感觉 T1 很像 dky 讲过的一道中北大学 ACM 题,T3 一看就是随机化,具体不知道怎么做。
T1 sb 题,直接取当前最小的光滑数,把它乘一个质因子放入候选集。类似《蚯蚓》开 B 个队列即可,\(O(KB)\)。
T3 推出了四元二次方程组,不会解。。。考虑过枚举 \(s\)。
T2 貌似可以状压?两个质因子的情况特判就行了。
7.40 开始写 T1,最初 RE 了,加上判断队列为空就过了所有样例,看一眼才 8.00?想了想没什么可写挂挂的地方,时间又开了 \(2\)s,不管了。
T3 想了一会突然想到可以把 \(scale\times\sin(\theta),scale\times\cos(\theta)\) 看作两个变量,那就变成了四元一次方程。随便找两个点是正确的概率为 \(\frac 34\),跑个 \(30\) 次应该没问题,后来发现它没说无解怎么办,那直接 for(;;)
就行了。当时以为高斯消元的复杂度和 \(O(n)\) 检验是乘起来的,于是决定手解方程。推了两个未知数式子就很恶心了,准备以后再说。
写完过了小样例,测速发现 T 了,而且很久跑不出来,先去写了 T2 部分分,期间因为除以 \(0\) 和质因子大于 \(\sqrt n\) 死过
回来看 T3,还是跑不出来,怀疑假了。重拿一张草稿纸完整地过了一遍,确定没问题,开始卡常数,但还是过不去。当时加了一句剪枝:若从 \(\sin,\cos\) 算出的 \(\theta\) 不一样就跳过,删了就能跑出来,但没有细想。。。
res
rk4 100+12+60
T1 开 \(1s\) 都可以
T2 在 \(n\) 是质数时挂了,其他情况未知
T3 就是正解,WA 了。
rk1 yzf 100+76+30
rk2 李嘉明 50+56+90
反思
考场上思考方式还是有问题,T2 T3 都出现过错误的类似情况,但只想到了体现出来的部分,没有细想,这也是依赖 gdb 带来的后果。
6 月的时候算是减少了 gdb 的使用,但还是不够,尽量少调试,多肉眼观察。
思考的时候也要深入,不要局限在眼下,要联想到其他情况/算法
Smooth
考场代码
int k,b;
const int p[] = {0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
queue<LL> que[16];
int find() {
int res = 1;
For(i,2,b) if( !que[i].empty() && que[i].front() < que[res].front() ) res = i;
return res;
}
signed main() {
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
read(b,k);
que[1].push(1);
while( --k ) {
int u = find(); LL val = que[u].front(); que[u].pop();
For(i,u,b) que[i].push(val*p[i]);
// printf("@ %lld\n",val);
}
write(que[find()].front());
return iocl();
}
Six
爆搜+记忆化就能过
状态是一个三元组:序列长度 \(l\),序列中有的质因子集合 \(s\),在不同数中出现过的质因子对(可能一对的两个质因子相同)集合 \(t\)。
解释一下 \(t\):不同数是为了避免同一个数标记了好几个质因子,质因子对是为了避免新加入数的质因子分布在前面不同的数中
说不太清楚,可以手模一下下面的序列(插入最后一个数):
\(6,6\) 合法
\(2,3,6\) 非法
\(6,2,3\) 合法
关于复杂度:\(n\) 的约数个数是 \(10^4\) 级别的,长度上界是 \(12\),而每个长度的状态数看似是 \(2^6\times2^{\binom62+6}\),但实际上约为 \(50000\)——官方sol。不会算,只会爆搜证明。
code
这份代码经过卡常复杂度瓶颈已经不在 dfs,而是分解质因数和预处理约数。
#define int unsigned
#define LL ULL
const int N = 1e6, mod = 1e9+7;
LL n;
int cnt=-1,m,po;
LL p[7],c[7],d[N],state[N],id[7][7];
unordered_map<int,int> vis[14][1<<7];
int dfs(int l,int s,LL t) {
if( vis[l][s][t] ) return vis[l][s][t];
int res = 1;
For(i,1,m) {
LL tt = t;
For(j,0,cnt) if( state[i] & (1<<j) )
For(k,j,cnt) if( state[i] & (1<<k) && (t & id[j][k]) ) goto TO;
For(j,0,cnt) if( state[i] & (1<<j) )
For(k,0,cnt) if( s & (1<<k) ) tt |= id[j][k];
res += dfs(l+1,s|state[i],tt);
if( res >= mod ) res -= mod;
TO:;
}
return vis[l][s][t] = res;
}
signed main() {
id[0][0]=1,id[0][1]=2,id[0][2]=4,id[0][3]=8,id[0][4]=16,id[0][5]=32,
id[1][0]=2,id[1][1]=64,id[1][2]=128,id[1][3]=256,id[1][4]=512,id[1][5]=1024,
id[2][0]=4,id[2][1]=128,id[2][2]=2048,id[2][3]=4096,id[2][4]=8192,id[2][5]=16384,
id[3][0]=8,id[3][1]=256,id[3][2]=4096,id[3][3]=32768,id[3][4]=65536,id[3][5]=131072,
id[4][0]=16,id[4][1]=512,id[4][2]=8192,id[4][3]=65536,id[4][4]=262144,id[4][5]=524288,
id[5][0]=32,id[5][1]=1024,id[5][2]=16384,id[5][3]=131072,id[5][4]=524288,id[5][5]=1048576;
read(n);
for(LL i = 2; i*i <= n; ++i) if( !(n % i) ) {
d[++m] = i;
if( n/i != i ) d[++m] = n/i;
}
d[++m] = n;
while( n > 1 ) {
++cnt;
for(LL i = 2; i*i <= n; ++i) if( !(n % i) ) { p[cnt] = i; break; }
if( !p[cnt] ) p[cnt] = n;
for(; !(n % p[cnt]); n /= p[cnt]) ++c[cnt];
}
For(i,1,m) For(j,0,cnt) if( !(d[i] % p[j]) ) state[i] |= 1<<j;
write(dfs(0,0,0)-1);
return iocl();
}
DP by 沈子舜
#include<bits/stdc++.h>
using namespace std;
#define uu unsigned
#define scanf abc=scanf
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define forg(i,x) for(int i=fir[x];i;i=nxt[i])
int abc;
typedef pair<int,int>pii;
typedef long long ll;
typedef uu long long ull;
typedef vector<int>VI;
inline int rd(int l,int r){return rand()%(r-l+1)+l;}
const int mod=1e9+7;
ll X;int m,v[7],n;
int zd[64],U;
bool cmp1(int x,int y){return zd[x]<zd[y];}
struct jg{
int n,a[7];
bool operator<(const jg&b)const{if(n!=b.n)return n<b.n;for(int i=1;i<=n;++i)if(a[i]!=b.a[i])return a[i]<b.a[i];return 0;}
void px(){sort(a+1,a+n+1,cmp1);}
}oo[903];
int xl[7];
map<jg,int>mp;
void dfs(int z=(1<<m)-1,int d=0){
if(!z){
jg k;k.n=d;for(int i=1;i<=d;++i)k.a[i]=xl[i];
oo[++n]=k;return;
}
int zz=z&-z;
for(int i=z^zz;~i;--i){i&=z^zz;xl[d+1]=zz|i,dfs(z^(zz|i),d+1);}
}
ll dp[13][64][903],vv[64];
int gxh(int a[]){jg k;k.n=a[0];for(int i=1;i<=k.n;++i)k.a[i]=a[i];k.px();return assert(mp[k]),mp[k];}
int to(int a[],int z,int zz){
static int b[7];int n=a[0],n1=0;
for(int i=1;i<=n;++i){int t=a[i]&zz;if(t)b[++n1]=t;}
int t=z&zz;if(t)b[++n1]=t;
b[0]=n1;return gxh(b);
}
int main(){
scanf("%lld",&X);
for(int i=0;i<64;++i)for(int j=5;~j;--j)if(i>>j&1)zd[i]=j;
for(int i=2;1ll*i*i<=X;++i)if(X%i==0){
int c=0;while(X%i==0)X/=i,++c;
v[m++]=c;
}
if(X>1)v[m++]=1;
U=(1<<m),--U;
for(int i=0;i<(1<<m);++i)dfs(i);
for(int i=1;i<=n;++i)mp[oo[i]]=i;
for(int i=1;i<=n;++i){
jg o=oo[i];
xl[0]=o.n;for(int j=1;j<=o.n;++j)xl[j]=o.a[j];
// cout<<gxh(xl)<<endl;
assert(gxh(xl));
}
// return 3;
dp[0][0][1]=1;
ll ans=0;
vv[0]=1;for(int i=1;i<=U;++i){vv[i]=1;for(int j=0;j<m;++j)if(i>>j&1)vv[i]=vv[i]*v[j]%mod;}
for(int t=0;t<=m*2;++t)for(int j=0;j<(1<<m);++j)for(int k=1;k<=n;++k)if(dp[t][j][k]){
ans+=dp[t][j][k];
jg o=oo[k];xl[0]=o.n;for(int i=1;i<=o.n;++i)xl[i]=o.a[i];
for(int z=1;z<(1<<m);++z)if((z&j)==0){
assert(vv[z]);
int c=0,zz=0;for(int i=1;i<=o.n;++i)if(z&xl[i])++c;
for(int i=1;i<=o.n;++i)zz|=z&xl[i];
if(c<=1)(dp[t+1][j|zz][to(xl,z,U^zz)]+=dp[t][j][k]*vv[z])%=mod;
}
}
--ans;
ans=(ans%mod+mod)%mod;printf("%lld\n",ans);
return 0;
}
Walker
只考虑一个 \(2\pi\) 范围。考场做法的问题是 \(\sin,\cos\) 会确定唯一的 \(\theta\),但如果只用 asin
算的话有两个 \(\theta\) 都满足,因此有 \(\frac 12\) 的概率 WA。应该在算出 \(\theta\) 后检验一下 \(\cos\) 是否满足,不满足则乘 \(-1\)(高中三角函数知识)
code
直接在考场代码上改的,因此保留了卡常部分(其实不必要),非常丑陋mt19937 mt(time(0));
const int N = 1e5+5;
int n;
struct Node { double sx,sy,tx,ty; } p[N];
#define sx(x) p[x].sx
#define sy(x) p[x].sy
#define tx(x) p[x].tx
#define ty(x) p[x].ty
const double eps = 1e-6, pi = acos(-1);
double s,th,dx,dy,a,b,f[6][6];
map<PII,bool> vis;
int rnd() { return mt()%n+1; }
bool equ(double x,double y) { return fabs(x-y) < eps; }
void work(int x,int y) {
f[1][1]=-sy(x),f[1][2]=sx(x),f[1][3]=1,f[1][4]=0,f[1][5]=tx(x),
f[2][1]=sx(x),f[2][2]=sy(x),f[2][3]=0,f[2][4]=1,f[2][5]=ty(x),
f[3][1]=-sy(y),f[3][2]=sx(y),f[3][3]=1,f[3][4]=0,f[3][5]=tx(y),
f[4][1]=sx(y),f[4][2]=sy(y),f[4][3]=0,f[4][4]=1,f[4][5]=ty(y);
For(i,1,4) {
int p = i;
if( i < 4 ) {
if( fabs(f[4][i]) > fabs(f[p][i])+eps ) p = 4;
if( i < 3 ) {
if( fabs(f[3][i]) > fabs(f[p][i])+eps ) p = 3;
if( i < 2 ) if( fabs(f[2][i]) > fabs(f[p][i])+eps ) p = 2;
}
}
if( p != i ) swap(f[i],f[p]);
f[i][5] /= f[i][i], f[i][4] /= f[i][i];
if( i <= 3 ) {
f[i][3] /= f[i][i];
if( i <= 2 ) {
f[i][2] /= f[i][i];
if( i <= 1 ) f[i][1] /= f[i][i];
}
}
if( i != 1 ) rFor(k,5,i) f[1][k] -= f[1][i] * f[i][k];
if( i != 2 ) rFor(k,5,i) f[2][k] -= f[2][i] * f[i][k];
if( i != 3 ) rFor(k,5,i) f[3][k] -= f[3][i] * f[i][k];
if( i != 4 ) rFor(k,5,i) f[4][k] -= f[4][i] * f[i][k];
}
a = f[1][5], b = f[2][5], dx = f[3][5], dy = f[4][5];
s = sqrt(a*a+b*b), th = acos(b/s);
if( !equ(sin(th)*s,a) ) th = -th;
}
signed main() {
// printf("%.1lf\n\n",sin(0));
// freopen("a.in","r",stdin);
// freopen("c1.out","w",stdout);
scanf("%d",&n);
For(i,1,n) scanf("%lf%lf%lf%lf",&sx(i),&sy(i),&tx(i),&ty(i));
shuffle(p+1,p+n+1,mt);
for(int i,j;;) {
do { i = rnd(), j = rnd(); } while( vis.count(MP(i,j)) );
vis[MP(i,j)] = vis[MP(j,i)] = 1;
work(i,j);
// th = 2.687435, s = 3.306753, dx = 2580.976362, dy = 2063.148692;
if( s < -eps || 10+eps < s ) continue;
int ok = 0, k;
for(k = 1; k+5 <= n; k += 6) {
if( equ(-a*sy(k)+b*sx(k)+dx,tx(k)) && equ(a*sx(k)+b*sy(k)+dy,ty(k)) ) ++ok;
if( equ(-a*sy(k+1)+b*sx(k+1)+dx,tx(k+1)) && equ(a*sx(k+1)+b*sy(k+1)+dy,ty(k+1)) ) ++ok;
if( equ(-a*sy(k+2)+b*sx(k+2)+dx,tx(k+2)) && equ(a*sx(k+2)+b*sy(k+2)+dy,ty(k+2)) ) ++ok;
if( equ(-a*sy(k+3)+b*sx(k+3)+dx,tx(k+3)) && equ(a*sx(k+3)+b*sy(k+3)+dy,ty(k+3)) ) ++ok;
if( equ(-a*sy(k+4)+b*sx(k+4)+dx,tx(k+4)) && equ(a*sx(k+4)+b*sy(k+4)+dy,ty(k+4)) ) ++ok;
if( equ(-a*sy(k+5)+b*sx(k+5)+dx,tx(k+5)) && equ(a*sx(k+5)+b*sy(k+5)+dy,ty(k+5)) ) ++ok;
}
for(; k <= n; ++k) if( equ(-a*sy(k)+b*sx(k)+dx,tx(k)) && !equ(a*sx(k)+b*sy(k)+dy,ty(k)) ) ++ok;
if( ok < (n+1)/2 ) continue;
// printf("@ %.3lf %.3lf\n",a,b);
printf("%.12lf\n%.12lf\n%.12lf %.12lf",th,s,dx,dy);
return 0;
}
}