• 20180613小测


    这题真是OI题?

    T1:

    就是给你一个不明觉厉的递推式然后计算东西啦。
    首先我们能用long double写一个暴力,发现前几项越来越小,后几项越来越大,明显不对......
    考虑为什么,因为计算机中的浮点数是有误差的,这样推的话,误差会被放大到n!级,直接GG!
    应该怎样做?手玩了半天发现没什么通项公式,难道写一个带压位FFT能做除法的高精度小数类?然后再求一个3w位有效数字的e?人干事,弃坑弃坑......
    于是写了10分暴力。由于没有删调试语句爆了零。
    考虑正解怎么做(抄题解?):
    首先我们有一个结论:

    于是我们可以这样从后向前递推f(n),不存在精度误差。

    (SDFZ某神仙:我观察到这东西绝对值越来越小,于是可以令f(1e5)=0,然后逆推f(n),于是就这样AC了此题)
    如何证明这个结论?
    首先我们先构造一个积分:

    考虑如何计算?首先我们有:

    我们令u,v等于如下值,则有:

    我们钦定g,h为如下意义:

    则有:

    没错,这东西就是f了。
    此外我们有:

    两边同时求积分,可得:

    也就是:

    于是我们就证明完了......
    (话说这真不是数竞巨佬的来强行出题了?)
    考场爆零代码:

     1 #include<cstdio>
     2 #include<cmath>
     3 typedef long double ldb;
     4 const int maxn=1e4+1e2;
     5 const ldb e = exp(1);
     6 
     7 ldb f[maxn];
     8 
     9 int main() {
    10     static int n;
    11     scanf("%d",&n) , *f = 1 - 1 / e;
    12     for(int i=1;i<=n;i++) f[i] = 1 - i * f[i-1];
    13     printf("%0.4Lf
    ",120/e-44);
    14     printf("%0.4Lf
    ",f[n]);
    15     return 0;
    16 }
    View Code

    正解代码:

     1 #include<cstdio>
     2 #include<cmath>
     3 typedef long double ldb;
     4 using namespace std;
     5 const int maxn=1e5+1e2,lim=1e5;
     6 const ldb e = exp(1);
     7 
     8 ldb f[maxn];
     9 
    10 inline void work() {
    11     f[lim] = ( 1 / ( lim + 1 ) + 1 / ( ( lim + 1 ) * e ) ) / 2.0;
    12     for(int i=lim;i;i--) f[i-1] = ( 1 - f[i] ) / i;
    13 }
    14 
    15 int main() {
    16     static int n;
    17     scanf("%d",&n) , work() , printf("%0.4Lf
    ",f[n]);
    18     return 0;
    19 }
    View Code


    T2:


    这题什么鬼......
    首先不共线的三点确定一个平面,那么我们能找不共线的三个点,钦定第一个点坐标为(0,0),第二个点在x轴上,第三个点纵坐标非负,这样就确定平面了。
    然后轻松地解方程求出其他所有点的坐标,因为题目保证有解,不会存在冲突的。
    但是细节很多啊......
    首先对于重合的点,我们要先用一个并查集把它们缩起来,否则如果第一个点和第二个点重合了,这题GG。
    此外第二个和第三个点坐标的计算方法是要单独写的......
    另外,如果前三个基准点共线的话,我们需要直接重选第三个基准点(显然不用重新计算共线那个点的坐标,因为它的位置是确定的)。
    然后就可以AC啦!
    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #define debug cerr
     7 typedef long double ldb;
     8 using namespace std;
     9 const int maxn=1e2+1e1;
    10 const ldb eps = 1e-4;
    11 
    12 inline ldb sq(const ldb &x) {
    13     return x * x;
    14 }
    15 ldb in[maxn][maxn],x[maxn],y[maxn];
    16 int n,sec,thr;
    17 
    18 inline void calc_second() {
    19     x[sec] = in[1][sec];
    20 }
    21 inline void calc_third() {
    22     const ldb r1 = in[1][thr] , r2 = in[sec][thr] , rt = in[1][sec];
    23     const ldb rit = sq(r2) - sq(r1) - sq(rt);
    24     x[thr] = rit / ( -2 * x[sec] ) , y[thr] = sqrt( sq(r1) - sq(x[thr]) );
    25 }
    26 inline void calc_kth(int k) {
    27     const ldb r1 = in[1][k] , r2 = in[sec][k] , r3 = in[thr][k];
    28     const ldb rit = sq(r2) - sq(r1) - sq(in[1][sec]);
    29     x[k] = rit / ( -2 * x[sec] );
    30     const ldb rit2 = sq(r3) - sq(r1) - sq(in[1][thr]) + 2 * x[thr] * x[k];
    31     y[k] = rit2 / ( -2 * y[thr] );
    32 }
    33 inline bool same_line() {
    34     const ldb dx2 = x[sec] - x[1] , dy2 = y[sec] - y[1];
    35     const ldb dx3 = x[thr] - x[1] , dy3 = y[thr] - y[1];
    36     if( fabs( dx2 * dy3 - dx3 * dy2 ) <= eps ) return 1;
    37     return 0;
    38 }
    39 
    40 struct UnionFindSet {
    41     int fa[maxn];
    42     inline int findfa(int x) {
    43         return fa[x] == x ? x : fa[x] = findfa(fa[x]);
    44     }
    45     inline void merge(int x,int y) {
    46         if( findfa(x) != findfa(y) ) fa[findfa(y)] = findfa(x);
    47     }
    48     inline void init() {
    49         for(int i=1;i<=n;i++) fa[i] = i;
    50     }
    51 }ufs;
    52 
    53 inline ldb dis(int i,int j) {
    54     return sqrt(sq(x[ufs.findfa(i)]-x[ufs.findfa(j)])+sq(y[ufs.findfa(i)]-y[ufs.findfa(j)]));
    55 }
    56 
    57 int main() {
    58     scanf("%d",&n) , ufs.init();
    59     for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) {
    60         scanf("%Lf",in[i]+j);
    61         if( i < j && fabs(in[i][j]) <= eps ) ufs.merge(i,j);
    62     }
    63     for(int i=2;i<=n;i++) if( ufs.findfa(i) == i ) {
    64         if( !sec ) sec = i;
    65         else if( !thr ) {thr = i; break;}
    66     }
    67     if( sec ) calc_second();
    68     if( thr ) calc_third();
    69     for(int i=thr+1;i<=n;i++) if( ufs.findfa(i) == i ) {
    70         if( same_line() ) thr = i , calc_third();
    71         else calc_kth(i);
    72     }
    73     for(int i=1;i<=n;i++) printf("%Lf %Lf
    ",x[ufs.findfa(i)],y[ufs.findfa(i)]);
    74     return 0;
    75 }
    View Code


    T3:

    题目描述就是给你一个矩阵的第一行,让你构造一个值域满足要求的矩阵使其行列式为1。
    由于矩阵转置行列式不变,我们可以先把第一行转置为第一列,最后再转置回来。
    由于题目保证存在两个数gcd为1,那么我们可以枚举是哪两个数的gcd为1,用辗转相除消元把矩阵的第一列消成仅有一个1。
    然后再枚举对角线上的值是+1还是-1,把消元的过程逆回去,看值域是否满足要求。
    为什么要两遍枚举?为了保证不把有解的情况由于值域问题判定为无解。
    于是这样写就能获得90分啦!
    (为什么少10分?因为我有一个地方的swap没有应用上。话说这样才只扣10分)
    考场90分代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cstdlib>
     6 #define debug cout
     7 typedef long long int lli;
     8 using namespace std;
     9 const int maxn=7,lim=2e3;
    10 
    11 inline lli gcd(lli x,lli y) {
    12     if( !x || !y ) return x | y;
    13     register lli t;
    14     while( ( t = x % y ) ) x = y , y = t;
    15     return y;
    16 }
    17 
    18 lli in[maxn],way[maxn],ans[maxn][maxn];
    19 lli ope[maxn*maxn*maxn],sou[maxn*maxn*maxn],tar[maxn*maxn*maxn],mul[maxn*maxn*maxn];
    20 int n,fs,cnt,lastnum;
    21 
    22 inline bool judge() {
    23     for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if( abs(ans[i][j]) > lim ) return 0;
    24     return 1;
    25 }
    26 inline bool solve_sta(int ss) {
    27     memset(ans,0,sizeof(ans));
    28     int pi = 1; ans[1][1] = 1;
    29     for(int i=2;i<=n;i++) {
    30         if( ss & ( 1 << ( i - 2 ) ) ) ans[i][i] = -1;
    31         else ans[i][i] = 1;
    32         pi *= ans[i][i];
    33     }
    34     if( pi != lastnum ) return 0;
    35     for(int i=cnt;i;i--) {
    36         if( ope[i] == 1 ) { // swap
    37             for(int j=1;j<=n;j++) swap(ans[sou[i]][j],ans[tar[i]][j]);
    38         } else {
    39             for(int j=1;j<=n;j++) ans[tar[i]][j] += ans[sou[i]][j] * mul[i];
    40         }
    41     }
    42     return judge();
    43 }
    44 inline bool getway() {
    45     static int lasti=1,lastj=0;
    46     cnt = 0 , lastnum = 1;
    47     for(int i=1;i<=n;i++) way[i] = in[i];
    48     for(;lasti<=n;lasti++,lastj=0) {
    49         for(lastj++;lastj<=n;lastj++) if( lasti != lastj && gcd(in[lasti],in[lastj]) == 1 ) {
    50             while( way[lasti] && way[lastj] ) {
    51                 if( way[lasti] > way[lastj] ) ope[++cnt] = 1 , sou[cnt] = lasti , tar[cnt] = lastj , lastnum *= -1 , swap(way[lasti],way[lastj]);
    52                 int t = way[lastj] / way[lasti];
    53                 ope[++cnt] = 0 , sou[cnt] = lasti , tar[cnt] = lastj , mul[cnt] = t , way[lastj] %= way[lasti];
    54             }
    55             if( !way[lasti] ) ope[++cnt] = 1 , sou[cnt] = lasti , tar[cnt] = lastj , lastnum *= -1 , swap(way[lasti],way[lastj]);
    56             if( lasti != 1 ) ope[++cnt] = 1 , sou[cnt] = lasti , tar[cnt] = 1 , lastnum *= 1;
    57             for(int j=2;j<=n;j++) if( way[j] ) ope[++cnt] = 0 , sou[cnt] = 1 , tar[cnt] = j , mul[cnt] = way[j] , way[j] = 0;
    58             return 1;
    59         }
    60     }
    61     return 0;
    62 }
    63 
    64 int main() {
    65     scanf("%d",&n) , fs = 1 << ( n - 1 );
    66     for(int i=1;i<=n;i++) scanf("%lld",in+i);
    67     for(int i=1;i<=n;i++) debug<<in[i]<<" "; debug<<endl;
    68     while(getway()) for(int ss=0;ss<fs;ss++) if( solve_sta(ss) ) {
    69         for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) printf("%lld%c",ans[j][i],j!=n?' ':'
    ');
    70         return 0;
    71     }
    72     puts("no solution");
    73     return 0;
    74 }
    View Code

    正解代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cstdlib>
     6 #define debug cout
     7 typedef long long int lli;
     8 using namespace std;
     9 const int maxn=7,lim=2e3;
    10 
    11 inline lli gcd(lli x,lli y) {
    12     if( !x || !y ) return x | y;
    13     register lli t;
    14     while( ( t = x % y ) ) x = y , y = t;
    15     return y;
    16 }
    17 
    18 lli in[maxn],way[maxn],ans[maxn][maxn];
    19 lli ope[maxn*maxn*maxn],sou[maxn*maxn*maxn],tar[maxn*maxn*maxn],mul[maxn*maxn*maxn];
    20 int n,fs,cnt,lastnum;
    21 
    22 inline bool judge() {
    23     for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if( abs(ans[i][j]) > lim ) return 0;
    24     return 1;
    25 }
    26 inline bool solve_sta(int ss) {
    27     memset(ans,0,sizeof(ans));
    28     int pi = 1; ans[1][1] = 1;
    29     for(int i=2;i<=n;i++) {
    30         if( ss & ( 1 << ( i - 2 ) ) ) ans[i][i] = -1;
    31         else ans[i][i] = 1;
    32         pi *= ans[i][i];
    33     }
    34     if( pi != lastnum ) return 0;
    35     for(int i=cnt;i;i--) {
    36         if( ope[i] == 1 ) { // swap
    37             for(int j=1;j<=n;j++) swap(ans[sou[i]][j],ans[tar[i]][j]);
    38         } else {
    39             for(int j=1;j<=n;j++) ans[tar[i]][j] += ans[sou[i]][j] * mul[i];
    40         }
    41     }
    42     return judge();
    43 }
    44 inline bool getway() {
    45     static int lasti=1,lastj=0;
    46     cnt = 0 , lastnum = 1;
    47     for(int i=1;i<=n;i++) way[i] = in[i];
    48     for(;lasti<=n;lasti++,lastj=0) {
    49         for(lastj++;lastj<=n;lastj++) if( lasti != lastj && gcd(in[lasti],in[lastj]) == 1 ) {
    50             while( way[lasti] && way[lastj] ) {
    51                 if( way[lasti] > way[lastj] ) ope[++cnt] = 1 , sou[cnt] = lasti , tar[cnt] = lastj , lastnum *= -1 , swap(way[lasti],way[lastj]);
    52                 int t = way[lastj] / way[lasti];
    53                 ope[++cnt] = 0 , sou[cnt] = lasti , tar[cnt] = lastj , mul[cnt] = t , way[lastj] %= way[lasti];
    54             }
    55             if( !way[lasti] ) ope[++cnt] = 1 , sou[cnt] = lasti , tar[cnt] = lastj , lastnum *= -1 , swap(way[lasti],way[lastj]);
    56             if( lasti != 1 ) ope[++cnt] = 1 , sou[cnt] = lasti , tar[cnt] = 1 , lastnum *= -1 , swap(way[lasti],way[1]);
    57             for(int j=2;j<=n;j++) if( way[j] ) ope[++cnt] = 0 , sou[cnt] = 1 , tar[cnt] = j , mul[cnt] = way[j] , way[j] = 0;
    58             return 1;
    59         }
    60     }
    61     return 0;
    62 }
    63 
    64 int main() {
    65     scanf("%d",&n) , fs = 1 << ( n - 1 );
    66     for(int i=1;i<=n;i++) scanf("%lld",in+i);
    67     while(getway()) for(int ss=0;ss<fs;ss++) if( solve_sta(ss) ) {
    68         for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) printf("%lld%c",ans[j][i],j!=n?' ':'
    ');
    69         return 0;
    70     }
    71     puts("no solution");
    72     return 0;
    73 }
    View Code


    这次只是在本学校Rank1了,SDFZ的那个神仙比我高10分......(话说我怎么会犯一些这么蠢的错误呢)

    「你说,那片云的背后,又会是什么呢?」
    「大概是一望无际的晴空吧。」
    「但是,这和我,又有什么关系呢?」
    只是这样想着,悲伤便满溢出来。

    (不是,为什么要加这段话?)

  • 相关阅读:
    Linux
    《移动群智感知网络》阅读笔记
    JAVA小记
    数据结构第十章:内部排序
    数据结构第九章:查找
    Oracle 物化视图(materialized view)
    Oracle Function 开启事务以及Update返回更新成功条数
    oracle存储过程的update并获取结果记录
    单例模式实现Demo
    winform BackgroundWorker组件操作
  • 原文地址:https://www.cnblogs.com/Cmd2001/p/9178356.html
Copyright © 2020-2023  润新知