20180110小测
于是我们今天有迎来了一次愉悦的小测。
早晨签到两发大吉,还有一个宜参加模拟赛?buff--。
然后看到了一个暴力分十分良心,怕不是正解不是给人写的了,buf--。
上午上了三节课,书丢了,下课提前走被老师训了,buf--。
中午13:40考试,迟到是必然的,怕不是要变成NOIP了,buf--。
就这样,我迎来了下午的考试。
T1:有毒的土豆排序:
什么?求逆序对?动态?怕不是树套树?
不行,这样卡n方了。
算了,想想正经方法:
动态维护变化量?写了,对拍,WA了。
肯定是我想的姿势不正确。
用一个树状数组暴力维护。修改的时候用vector记录位置和数值,数值重新排序。
好,70分到手。不管了。
这题目的正解是考虑操作的性质,如果一个数被操作过了那么他后面一定没有比他小的值,然后离线即可。
另外,题面出锅了!必须按照含等于进行计算。我用两次WA证明了这一点。
考场70分代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 const int maxn=1e3+1e2; 8 9 vector<int> poss; 10 int in[maxn],srt[maxn]; 11 int n,m,cnt,ans; 12 13 struct BinaryIndexTree { 14 int dat[maxn]; 15 16 #define lowbit(x) (x&-x) 17 18 inline void update(int pos,int x) { 19 while( pos <= n ) 20 dat[pos] += x, 21 pos += lowbit(pos); 22 } 23 inline int query(int pos) { 24 int ret = 0; 25 while( pos ) 26 ret += dat[pos], 27 pos -= lowbit(pos); 28 return ret; 29 } 30 inline void reset() { 31 memset(dat,0,sizeof(dat)); 32 } 33 }bit; 34 35 inline void getposs(int fst) { 36 poss.clear(); 37 poss.push_back(fst); 38 for(int i=fst+1;i<=n;i++) 39 if( in[i] < in[fst] ) 40 poss.push_back(i); 41 } 42 inline void replac() { 43 static vector<int> nums; 44 nums.clear(); 45 for(unsigned i=0;i<poss.size();i++) 46 nums.push_back(in[poss[i]]); 47 sort(nums.begin(),nums.end()); 48 for(unsigned i=0;i<poss.size();i++) 49 in[poss[i]] = nums[i]; 50 } 51 inline int calc() { 52 int ret = 0; 53 for(int i=1;i<=n;i++) { 54 ret += bit.query(n) - bit.query(in[i]); 55 bit.update(in[i],1); 56 } 57 return ret; 58 } 59 inline void work(int pos) { 60 getposs(pos); 61 replac(); 62 bit.reset(); 63 ans = calc(); 64 } 65 66 inline void init() { 67 memcpy(srt,in,sizeof(in)); 68 cnt = n; 69 sort(srt+1,srt+1+cnt); 70 cnt = unique(srt+1,srt+1+cnt) - srt - 1; 71 for(int i=1;i<=n;i++) 72 in[i] = lower_bound(srt+1,srt+1+cnt,in[i]) - srt; 73 74 for(int i=1;i<=n;i++) 75 poss.push_back(i); 76 ans = calc(); 77 } 78 79 int main() { 80 scanf("%d%d",&n,&m); 81 for(int i=1;i<=n;i++) 82 scanf("%d",in+i); 83 init(); 84 85 printf("%d\n",ans); 86 for(int j=1,p;j<=m;j++) { 87 scanf("%d",&p); 88 work(p); 89 printf("%d\n",ans); 90 } 91 92 return 0; 93 }
考后AC代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cctype> 5 #define lli long long int 6 #define lowbit(x) (x&-x) 7 using namespace std; 8 const int maxn=1e5+1e2; 9 const int inf=0x3f3f3f3f; 10 11 int in[maxn],srt[maxn],n,m,cnt; 12 lli iniv[maxn],delt[maxn]; 13 14 struct QNode { 15 int pos,t; 16 friend bool operator < (const QNode &a,const QNode &b) { 17 return a.pos < b.pos; 18 } 19 }ns[maxn]; 20 21 namespace Ini { 22 lli dat[maxn]; 23 inline void update(int pos,int x) { 24 while( pos <= n ) 25 dat[pos] += x, 26 pos += lowbit(pos); 27 } 28 inline lli query(int pos) { 29 lli ret = 0; 30 while( pos ) 31 ret += dat[pos], 32 pos -= lowbit(pos); 33 return ret; 34 } 35 } 36 namespace Bit { 37 int dat[maxn]; 38 inline void update(int pos,int x) { 39 while( pos <= cnt ) 40 dat[pos] = min( dat[pos] , x ), 41 pos += lowbit(pos); 42 } 43 inline int query(int pos) { 44 int ret = *dat; 45 while( pos ) 46 ret = min( ret , dat[pos] ), 47 pos -= lowbit(pos); 48 return ret; 49 } 50 inline void init() { 51 memset(dat,0x3f,sizeof(dat)); 52 } 53 } 54 55 inline void getans() { 56 for(int i=n;i;i--) { 57 Ini::update(in[i],1); 58 iniv[i] = Ini::query(in[i]-1); 59 delt[0] += iniv[i]; 60 } 61 62 int pp = 1; 63 for(int i=1;i<=n;i++) { 64 while( ns[pp].pos == i ) { 65 Bit::update(cnt-in[ns[pp].pos]+1,ns[pp].t); 66 ++pp; 67 } 68 int q = Bit::query(cnt-in[i]+1); 69 if( q != inf ) { 70 delt[q] -= iniv[i]; 71 } 72 } 73 for(int i=1;i<=m;i++) 74 delt[i] += delt[i-1]; 75 } 76 77 inline void init() { 78 Bit::init(); 79 80 sort(srt+1,srt+1+n); 81 cnt = unique(srt+1,srt+1+n) - srt - 1; 82 83 for(int i=1;i<=n;i++) 84 in[i] = lower_bound(srt+1,srt+1+cnt,in[i]) - srt; 85 86 sort(ns+1,ns+1+m); 87 } 88 89 inline int getint() { 90 int ret = 0 , ch; 91 do ch=getchar(); while( !isdigit(ch) ); 92 do ret=ret*10+ch-'0'; while( isdigit(ch=getchar()) ); 93 return ret; 94 } 95 int main() { 96 n = getint() , m = getint(); 97 for(int i=1;i<=n;i++) 98 srt[i] = in[i] = getint(); 99 for(int i=1;i<=m;i++) 100 ns[i] = (QNode){getint(),i}; 101 102 init(); 103 getans(); 104 105 for(int i=0;i<=m;i++) 106 printf("%lld\n",delt[i]); 107 108 return 0; 109 }
T2:窝瓜走路:
显然我先写的是这个题。
一看总共9个点,T的范围为long long,矩乘跑不了了。
看一下怎么矩乘,先跑出每对点的方案数,然后再9!枚举哪个点到哪个点。然后方案数连乘更新答案。
100分就这样吧。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define lli long long int 6 #define debug cout 7 using namespace std; 8 const int maxn=12; 9 const int mod = 1e9+7; 10 11 const int dx[]={-1,1,0,0,0},dy[]={0,0,-1,1,0}; 12 int pre[maxn]; 13 lli T,ans,now; 14 15 struct Matrix { 16 lli dat[maxn][maxn]; 17 Matrix(int tpe = 0) { 18 memset(dat,0,sizeof(dat)); 19 if( tpe ) 20 for(int i=1;i<=9;i++) 21 dat[i][i] = 1; 22 } 23 friend Matrix operator * (const Matrix &a,const Matrix &b) { 24 Matrix ret; 25 for(int i=1;i<=9;i++) 26 for(int j=1;j<=9;j++) 27 for(int k=1;k<=9;k++) 28 ret.dat[i][j] = ( ret.dat[i][j] + a.dat[i][k] * b.dat[k][j] % mod ) % mod; 29 return ret; 30 } 31 }base,way; 32 33 inline Matrix fastpow(const Matrix &base,lli tme) { 34 Matrix now = base , ret = Matrix(1); 35 while( tme ) { 36 if( tme & 1 ) 37 ret = ret * now; 38 now = now * now; 39 tme >>= 1; 40 } 41 return ret; 42 } 43 44 inline bool judge(int x,int y) { 45 return x > 0 && x <= 3 && y > 0 && y <= 3; 46 } 47 inline int cov(int x,int y) { 48 return ( x - 1 ) * 3 + y; 49 } 50 inline void init() { 51 for(int x=1;x<=3;x++) 52 for(int y=1;y<=3;y++) 53 for(int k=0;k<5;k++) { 54 const int tx = x + dx[k] , ty = y + dy[k]; 55 if( judge(tx,ty) ) 56 base.dat[cov(tx,ty)][cov(x,y)] = 1; 57 } 58 } 59 60 inline lli calc() { 61 lli ret = 1; 62 for(int i=1;i<=9;i++) 63 ret = ret * way.dat[i][pre[i]] % mod; 64 return ret; 65 } 66 inline void getans() { 67 init(); 68 way = fastpow(base,T); 69 70 for(int i=1;i<=9;i++) 71 pre[i] = i; 72 73 do { 74 ans = ( ans + calc() ) % mod; 75 } while( next_permutation(pre+1,pre+10) ); 76 } 77 78 int main() { 79 scanf("%lld",&T); 80 getans(); 81 82 printf("%lld\n",ans); 83 return 0; 84 }
T3:不知道起什么名字好的数学题
很显然的题目。
我一开始用μ反演,然后推出了一个可以用nloglogn筛出的东西,70分到手。
然后考虑怎么优化,提取了一个μ的前缀和,还有某个数的k次方的前缀和。
算法复杂度为n^(3/4),然而k次方的前缀和手玩玩不出来,弃坑。
正解:用φ反演。
然后杜教筛φ即可。
对于k次方的前缀和,我们能看出他是一个k+1次的多项式,然后高斯消元求解系数即可。
考场70分代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define lli long long int 6 #define debug cout 7 using namespace std; 8 const int maxn=1e6+1e2,lim=1e6; 9 const int mod=1e9+7; 10 11 lli sum[maxn]; 12 int n,k; 13 14 inline lli slowpow(lli base) { 15 register lli ret = 1; 16 for(register int i=k;i;i--) 17 ret = ret * base % mod; 18 return ret; 19 } 20 inline void pre() { 21 static lli pows[maxn]; 22 static int prime[maxn],mu[maxn],cnt; 23 static unsigned char vis[maxn]; 24 25 mu[1] = 1 , pows[1] = 1; 26 for(lli i=2;i<=n;i++) { 27 if( !vis[i] ) { 28 prime[++cnt] = i, 29 mu[i] = -1 , pows[i] = slowpow(i); 30 } 31 for(int j=1;j<=cnt&&i*prime[j]<=n;j++) { 32 const int tar = i * prime[j]; 33 vis[tar] = 1 , pows[tar] = pows[i] * pows[prime[j]] % mod; 34 if( ! ( i % prime[j] ) ) { 35 mu[tar] = 0; 36 break; 37 } 38 mu[tar] = -mu[i]; 39 } 40 } 41 for(lli i=1;i<=n;i++) 42 if( mu[i] ) { 43 for(lli j=1;i*j<=n;j++) 44 sum[i*j] += mu[i] * pows[j] % mod , 45 sum[i*j] %= mod; 46 } 47 for(int i=1;i<=n;i++) 48 sum[i] = ( ( sum[i] + sum[i-1] ) % mod + mod ) % mod; 49 } 50 51 inline lli getans() { 52 lli ret = 0; 53 for(lli i=1,j;i<=n;i=j+1) { 54 j = n / ( n / i ); 55 ret += ( sum[j] - sum[i-1] ) * ( n / i ) % mod * ( n / i ) % mod; 56 ret %= mod; 57 } 58 return ( ret + mod ) % mod; 59 } 60 61 int main() { 62 scanf("%d%d",&n,&k); 63 64 pre(); 65 66 printf("%lld\n",getans()); 67 68 return 0; 69 }
求解系数代码:
1 #include<bits/stdc++.h> 2 #define lli long long int 3 #define debug cout 4 using namespace std; 5 const int maxn=100; 6 const int mod=1e9+7; 7 8 lli f[maxn][maxn]; 9 int k; 10 11 inline lli rev(int base) { 12 lli now = base , ret = 1 , tme = mod - 2; 13 while(tme) { 14 if( tme & 1 ) 15 ret = ret * now % mod; 16 now = now * now % mod; 17 tme >>= 1; 18 } 19 debug<<"base = "<<base<<"ret = "<<ret<<endl; 20 return ret; 21 } 22 23 inline lli slowpow(lli base,int tme) { 24 lli ret = 1; 25 for(int t=tme;t;t--) 26 ret = ret * base % mod; 27 return ret; 28 } 29 inline lli g(lli x) { 30 lli ret = 0; 31 for(int i=1;i<=x;i++) 32 ret = ( ret + slowpow(i,k-1) ) % mod; 33 //debug<<"x = "<<x<<"ret = "<<ret<<endl; 34 return ret; 35 } 36 37 inline void gen() { 38 for(int i=1;i<=k+1;i++) { 39 for(int j=0;j<=k;j++) 40 f[i][j] = slowpow(i,j); 41 f[i][k+1] = g(i); 42 } 43 for(int i=0;i<=k;i++) 44 for(int j=0;j<=k+1;j++) 45 f[i][j] = f[i+1][j]; 46 } 47 48 inline void gauss() { 49 for(int i=0;i<=k;i++) { 50 int e = -1; 51 for(int j=i;j<=k;j++) 52 if( f[j][i] ) { 53 e = j; 54 break; 55 } 56 if( !~e ) { 57 puts("Unable to find a solution;"); 58 exit(0); 59 } 60 debug<<"i = "<<i<<"e = "<<e<<endl; 61 if( e != i ) { 62 for(int j=0;j<=k+1;j++) 63 swap(f[i][j],f[e][j]); 64 e = i; 65 } 66 lli r = rev(f[i][i]); 67 debug<<"fii = "<<f[i][i]<<"rev = "<<r<<endl; 68 for(int j=0;j<=k+1;j++) 69 f[i][j] = f[i][j] * r % mod; 70 for(int j=0;j<=k+1;j++) 71 debug<<f[i][j]<<" ";debug<<endl; 72 for(int j=0;j<=k;j++) 73 if( j != i && f[j][i] ) { 74 const lli del = f[j][i]; 75 for(int t=0;t<=k+1;t++) 76 f[j][t] = ( ( f[j][t] - f[i][t] * del % mod ) % mod + mod ) % mod; 77 } 78 } 79 } 80 81 inline void print() { 82 for(int i=0;i<=k;i++) { 83 for(int j=0;j<=k+1;j++) debug<<f[i][j]<<" ";debug<<endl; 84 } 85 } 86 int main() { 87 char com[100]; 88 scanf("%d",&k); 89 sprintf(com,"dat%d.txt",k); 90 ++k; 91 gen(); 92 print(); 93 gauss(); 94 debug<<"Ans = "<<endl; 95 print(); 96 freopen(com,"w",stdout); 97 printf("{"); 98 for(int i=0;i<=k;i++) 99 printf("%lld%c",f[i][k+1],i!=k?',':'}'); 100 }
考后AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define lli long long int 6 #define debug cout 7 using namespace std; 8 const int maxn=5e6+1e2,lim=5e6; 9 const int mod=1e9+7; 10 const int muls[6][7] = { 11 {0,0,0,0,0,0,0}, 12 {0,500000004,500000004,0,0,0,0}, 13 {0,166666668,500000004,333333336,0,0,0}, 14 {0,0,250000002,500000004,250000002,0,0}, 15 {0,766666672,0,333333336,500000004,400000003,0}, 16 {0,0,916666673,0,416666670,500000004,166666668} 17 }; 18 19 lli sum[maxn],mem[maxn]; 20 unsigned char vis[maxn]; 21 lli n; 22 int k; 23 24 inline lli gk(lli x) { 25 x %= mod; 26 lli ret = 0 , now = 1; 27 for(int i=0;i<=k+1;i++) { 28 ret += now * muls[k][i] % mod; 29 ret %= mod; 30 now = now * x % mod; 31 } 32 return ret; 33 } 34 35 inline void sieve() { 36 static int prime[maxn],cnt; 37 38 sum[1] = 1; 39 for(lli i=2;i<=lim;i++) { 40 if( !sum[i] ) { 41 prime[++cnt] = i , 42 sum[i] = i - 1; 43 } 44 for(int j=1;j<=cnt&&i*prime[j]<=lim;j++) { 45 const int tar = i * prime[j]; 46 if( ! ( i % prime[j] ) ) { 47 sum[tar] = sum[i] * prime[j]; 48 break; 49 } 50 sum[tar] = sum[i] * ( prime[j] - 1 ); 51 } 52 } 53 for(int i=1;i<=lim;i++) 54 sum[i] += sum[i-1] , 55 sum[i] %= mod; 56 } 57 58 inline lli inisum(lli x) { 59 x %= mod; 60 return ( x * ( x + 1 ) >> 1 ) % mod; 61 } 62 inline lli getsum(lli x) { 63 if( x <= lim ) 64 return sum[x]; 65 const int t = n / x; 66 if( vis[t] ) 67 return mem[t]; 68 vis[t] = 1 , mem[t] = inisum(x); 69 for(lli i=2,j;i<=x;i=j+1) { 70 j = x / ( x / i ); 71 mem[t] -= ( j - i + 1 ) * getsum( x / i ) % mod; 72 mem[t] %= mod; 73 } 74 return mem[t] = ( mem[t] + mod ) % mod; 75 } 76 77 inline lli calcr(lli x) { 78 lli ret = ( getsum(x) << 1 ) % mod - 1; 79 return ( ret % mod + mod ) % mod; 80 } 81 inline lli getans() { 82 lli ret = 0; 83 for(lli i=1,j;i<=n;i=j+1) { 84 j = n / ( n / i ); 85 ret += ( ( gk(j) - gk(i-1) ) % mod + mod ) % mod * calcr( n / i ) % mod; 86 ret %= mod; 87 } 88 return ( ret + mod ) % mod; 89 } 90 91 int main() { 92 scanf("%lld%d",&n,&k); 93 sieve(); 94 95 printf("%lld\n",getans()); 96 97 return 0; 98 }
最后补一张排名:
为何常数如此之大,然后我掉rank了。