zoukankan      html  css  js  c++  java
  • FOJ 10月赛题 FOJ2198~2204

    A题。

    发现是递推可以解决这道题,a[n]=6*a[n-1]-a[n-2]。因为是求和,可以通过一个三维矩阵加速整个计算过程,主要是预处理出2^k时的矩阵,可以通过这道题

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #define LL long long
     6 using namespace std;
     7 
     8 const int MOD=1e9+7;
     9 
    10 
    11 int quick(int a,int b){
    12     int res=0;
    13     while(b){
    14         if(b&1){
    15             res+=a;
    16             if(res>=MOD) res-=MOD;
    17         }
    18         b>>=1;
    19         a+=a;
    20         if(a>=MOD) a-=MOD;
    21     //    cout<<"YES"<<endl;
    22     }
    23     return res;
    24 }
    25 
    26 struct Matrix{
    27     int a[3][3];
    28     void init(){
    29         for(int i=0;i<3;i++)
    30             for(int j=0;j<3;j++) a[i][j]=0;
    31     }
    32 /*    Matrix operator= (Matrix p){
    33         for(int i=0;i<3;i++){
    34             for(int j=0;j<3;j++) a[i][j]=p.a[i][j];
    35         }
    36         return *this;
    37     }*/
    38     Matrix operator* (Matrix s){
    39         Matrix res;
    40         for(int i=0;i<3;i++)
    41             for(int j=0;j<3;j++){
    42                 res.a[i][j]=0;
    43                 for(int k=0;k<3;k++){
    44                     res.a[i][j]+=(long long)a[i][k]*s.a[k][j]%MOD;
    45                     if(res.a[i][j]>=MOD) res.a[i][j]-=MOD;
    46                 ///    cout<<"YES"<<endl;
    47                 }
    48             }
    49         return res;
    50     }
    51 }a,power[100];
    52 
    53 
    54 void init(){
    55     power[0].a[0][0]=1,power[0].a[0][1]=0,power[0].a[0][2]=0;
    56     power[0].a[1][0]=1,power[0].a[1][1]=6,power[0].a[1][2]=1;
    57     power[0].a[2][0]=0,power[0].a[2][1]=MOD-1,power[0].a[2][2]=0;
    58     
    59     a.a[0][0]=0,a.a[0][1]=6,a.a[0][2]=1;
    60     a.a[1][0]=0,a.a[1][1]=0,a.a[1][2]=0;
    61     a.a[2][0]=0,a.a[2][1]=0,a.a[2][2]=0;
    62 
    63     for(LL i=1;i<70;i++){
    64         power[i]=power[i-1]*power[i-1];
    65     }
    66 /*    for(int i=0;i<3;i++){
    67         for(int j=0;j<3;j++)
    68             cout<<power[0].a[i][j]<<" ";
    69         cout<<endl;
    70     }*/
    71 }
    72 
    73 
    74 int main(){
    75     init();
    76     int T;LL n;
    77     scanf("%d",&T);
    78     while(T--){
    79         scanf("%I64d",&n);    /////不能用lld
    80         Matrix ans=a;
    81         int cnt=0;
    82         while(n){
    83             if(n&1) ans=ans*power[cnt];
    84             n>>=1;
    85             cnt++;
    86         }
    87         printf("%d
    ",ans.a[0][0]);
    88     }
    89     
    90     return 0;
    91 }
    View Code

    B题。留坑

    C题。这道题其实和G题一样,DP可以解决。记录前两个位置的状态,限制第三个位置的状态,进行转移即可。因为是一个环,所以,在选择最后两个位置的状态时要和最开始的两个位置相容,进行枚举即可。所以要计算四种开始的状态,分别是(00),(01)(10)(11)。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 
     6 using namespace std;
     7 
     8 int dp[2][2][1005][1005][2][2];//////fisrt ,second
     9 const int MOD=1e9+7;
    10 
    11 int add(int a,int b){
    12     a+=b;
    13     if(a>MOD) a-=MOD;
    14     return a;
    15 }
    16 
    17 
    18 int main(){    
    19     int T,n,p;
    20     scanf("%d",&T);
    21         memset(dp,0,sizeof(dp));
    22         dp[0][1][2][1][0][1]=dp[1][0][2][1][1][0]=dp[1][1][2][2][1][1]=dp[0][0][2][0][0][0]=1;
    23         for(int fst=0;fst<2;fst++){
    24             for(int sec=0;sec<2;sec++){
    25                 for(int i=3;i<=1000;i++){
    26                     for(int k=0;k<=min(i,1000);k++){
    27                         ///select
    28                         if(k){
    29                             dp[fst][sec][i][k][1][1]=add(dp[fst][sec][i][k][1][1],dp[fst][sec][i-1][k-1][0][1]);
    30                             dp[fst][sec][i][k][0][1]=add(dp[fst][sec][i][k][0][1],dp[fst][sec][i-1][k-1][0][0]);
    31                         }
    32                         ///un select
    33                         dp[fst][sec][i][k][1][0]=add(dp[fst][sec][i][k][1][0],add(dp[fst][sec][i-1][k][1][1],dp[fst][sec][i-1][k][0][1]));
    34                         dp[fst][sec][i][k][0][0]=add(dp[fst][sec][i][k][0][0],add(dp[fst][sec][i-1][k][0][0],dp[fst][sec][i-1][k][1][0]));
    35                     }
    36                 }
    37             }
    38         }
    39     while(T--){
    40         scanf("%d%d",&n,&p);
    41         int ans=0;
    42         for(int fst=0;fst<2;fst++){
    43             for(int sec=0;sec<2;sec++){
    44                 for(int i=0;i<2;i++){
    45                     for(int j=0;j<2;j++){
    46                         if(!(fst&i)&&!(sec&j)){
    47                             ans=add(ans,dp[fst][sec][n][p][i][j]);
    48                             ans=add(ans,dp[fst][sec][n][p][i][j]);
    49                         }
    50                     }
    51                 }
    52             }
    53         }
    54         printf("%d
    ",ans);
    55     }
    56     return 0;
    57 }
    View Code

    D题。这道题是学习窝bin的。线段树可以解决。

    首先,要知道的是gcd(a1,a2)=gcd(a1,a1-a2)。则gcd(x-a1,x-a2)=gcd(x-a1,a1-a2)。

    那么,对于gcd(x-a1,x-a2,x-a3.....x-an)=gcd(x-a1,a1-a2,a2-a3.....a[n-1]-a[n])。使用线段树来维护a1-a2,a2-a3....这个差分序列,同时记录x的值以及头尾两个a1,an的值。使用线段树更新,即可。具体可看代码.

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <iostream>
      4 #include <algorithm>
      5 #include <vector>
      6 #include <queue>
      7 #include <set>
      8 #include <map>
      9 #include <string>
     10 #include <math.h>
     11 #include <stdlib.h>
     12 #include <time.h>
     13 using namespace std;
     14 const int MAXN = 100010;
     15 long long gcd(long long a,long long b){
     16     if(b == 0)return a;
     17     return gcd(b,a%b);
     18 }
     19 struct Node {
     20     int l,r;
     21     int a,b;
     22     int first,last;
     23     int g;
     24     int val;
     25 }segTree[MAXN<<2];
     26 void push_up(int i) {
     27     segTree[i].first = segTree[i<<1].first;
     28     segTree[i].last = segTree[(i<<1)|1].last;
     29     segTree[i].val = gcd(segTree[i<<1].val,segTree[(i<<1)|1].val);
     30     segTree[i].val = gcd(segTree[i].val,abs(segTree[i<<1].last-segTree[(i<<1)|1].first));
     31     segTree[i].g = gcd(segTree[i].val,segTree[i].first);
     32 }
     33 void Update_node(int i,int a,int b) {
     34     segTree[i].first = a*segTree[i].first+b;
     35     segTree[i].last = a*segTree[i].last+b;
     36     segTree[i].g = gcd(segTree[i].first,segTree[i].val);
     37     segTree[i].a *= a;
     38     segTree[i].b = a*segTree[i].b+b;
     39 }
     40 void push_down(int i) {
     41     if(segTree[i].l == segTree[i].r)return;
     42     int a = segTree[i].a;
     43     int b = segTree[i].b;
     44     if(a != 1 || b != 0) {
     45         Update_node(i<<1,a,b);
     46         Update_node((i<<1)|1,a,b);
     47         a = 1;
     48         b = 0;
     49     }
     50 }
     51 int a[MAXN];
     52 void build(int i,int l,int r) {
     53     segTree[i].l = l;
     54     segTree[i].r = r;
     55     segTree[i].a = 1;
     56     segTree[i].b = 0;
     57     if(l == r) {
     58         segTree[i].first = a[l];
     59         segTree[i].last = a[l];
     60         segTree[i].val = 0;
     61         segTree[i].g = a[l];
     62         return;
     63     }
     64     int mid = (l+r)/2;
     65     build(i<<1,l,mid);
     66     build((i<<1)|1,mid+1,r);
     67     push_up(i);
     68 }
     69 void update(int i,int l,int r,int a,int b) {
     70     if(segTree[i].l == l && segTree[i].r == r) {
     71         Update_node(i,a,b);
     72         return;
     73     }
     74     push_down(i);
     75     int mid = (segTree[i].l+segTree[i].r)/2;
     76     if(r <= mid)update(i<<1,l,r,a,b);
     77     else if(l > mid)update((i<<1)|1,l,r,a,b);
     78     else {
     79         update(i<<1,l,mid,a,b);
     80         update((i<<1)|1,mid+1,r,a,b);
     81     }
     82     push_up(i);
     83 }
     84 int query(int i,int l,int r) {
     85     if(segTree[i].l == l && segTree[i].r == r)
     86         return segTree[i].g;
     87     push_down(i);
     88     int mid = (segTree[i].l+segTree[i].r)/2;
     89     if(r <= mid)return query(i<<1,l,r);
     90     else if (l > mid)return query((i<<1)|1,l,r);
     91     else return gcd(query(i<<1,l,mid),query((i<<1)|1,mid+1,r));
     92 }
     93 
     94 int main(){
     95     int n,m;
     96     while(scanf("%d%d",&n,&m) == 2) {
     97         for(int i = 1;i <= n;i++)scanf("%d",&a[i]);
     98         build(1,1,n);
     99         int op;
    100         int l,r,x;
    101         while(m--) {
    102             scanf("%d",&op);
    103             if(op == 1) {
    104                 scanf("%d%d%d",&l,&r,&x);
    105                 update(1,l,r,-1,x);
    106             } else {
    107                 scanf("%d%d",&l,&r);
    108                 printf("%d
    ",query(1,l,r));
    109             }
    110         }
    111     }
    112     return 0;
    113 }
    View Code

    E题推理。这里注意必须从说+号的人下手。由于有m个人说真话,假设说了+A的人都说了真话,那么-A的人就是假话,而说其他的+的人也说了假话,说其他-的人说了真话。这里统计说了真话的人,如果>m,则说了+A的人都说了假话。如果刚好,我们统计这种“刚好”有多少种,置为待定状态,把iscrime[A]=true。则对于说了A是罪犯的人,因无法判断A是否真的是罪犯,输出未定。如果iscrime[A]=false,对于说了A是罪犯的,则肯定是说了假话。对于A不是罪犯的,如果这时A是true,因为A未定,所以输出待定,否则,如果A是false,则肯定是说了真话,因为对于iscrime[A]=false的条件,只有当说真话的人肯定说了假话,亦即是说了+A的人肯定说了假话,才会是false。

    由于题目条件是肯定有解,所以如果“刚好”的情况只有一种,则谁说真谁说假是可以确定的。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int MAX=1e5+7;
    
    int say[MAX],vote[MAX],nvote[MAX],pcnt,ncnt;
    bool iscrime[MAX];
    
    int main(){
        int T,n,m;
        scanf("%d",&T);
        while(T--){
            pcnt=ncnt=0;
            scanf("%d%d",&n,&m);
            memset(vote,0,sizeof(vote));
            memset(nvote,0,sizeof(nvote));
            for(int i=1;i<=n;i++){
                scanf("%d",&say[i]);
                if(say[i]>0) vote[say[i]]++;
                else nvote[-say[i]]++;
                if(say[i]>0) pcnt++;
                else ncnt++;
            }
            memset(iscrime,false,sizeof(iscrime));
            int counts=0;
            for(int i=1;i<=n;i++){
                if(vote[i]+ncnt-nvote[i]==m){
                    iscrime[i]=true;
                    counts++;
                }
            }
            if(counts==1){
                int find;
                for(int i=1;i<=n;i++){
                    if(say[i]>0)
                        if(iscrime[say[i]]){
                            puts("Truth");
                        }
                        else puts("Lie");
                    else{
                        if(iscrime[-say[i]]){
                            puts("Lie");
                        }
                        else puts("Truth");
                    }
                }
            }
            else{
                for(int i=1;i<=n;i++){
                    if(say[i]>0){
                        if(iscrime[say[i]]){
                            puts("Not defined");
                        }
                        else puts("Lie");
                    }
                    else{
                        if(iscrime[-say[i]]){
                            puts("Not defined");
                        }
                        else puts("Truth");
                    }
                }
            }
                
        }
        return 0;
    }
    View Code

    F题使用set就可以解决了。

    G题,DP题。和C题是一样的。先枚举DP假如是一条直线时,连续的个数<=6个时的所有情况。再按这种方式枚举,减去因为首尾相连可能出现>=7的情况,就可以得到结果.

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int MAX=100005;
    const int MOD=2015;
    int dp[MAX][2][7];
    
    int main(){
        int n,T,icase=0;
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            printf("Case #%d: ",++icase);
            if(n<7){
                int ans=1;
                for(int i=1;i<=n;i++)
                    ans*=2;
        //        if(n==7) ans-=2;
                printf("%d
    ",ans%MOD);
                continue;
            }
            memset(dp,0,sizeof(dp));
            dp[1][0][1]=1; dp[1][1][1]=1;
            for(int i=2;i<=n;i++){
                for(int j=0;j<=1;j++)
                    for(int k=1;k<=6;k++){
                        if(k==1){
                            ///dp[i][j][k]=0;
                            for(int p=1;p<=6;p++)
                                dp[i][j][k]+=dp[i-1][j^1][p];
                            dp[i][j][k]%=MOD;
                        }
                        else{
                            //dp[i][j][k]=0;
                                dp[i][j][k]+=dp[i-1][j][k-1];
                            dp[i][j][k]%=MOD;
                        }
                    }
            }
            int ans=0;
                for(int j=0;j<=1;j++){
                    for(int k=1;k<=6;k++){
                        ans+=dp[n][j][k];
                    }
                    ans%=MOD;
                }
            //    cout<<ans<<endl;
            memset(dp,0,sizeof(dp));
            for(int e=1;e<=6;e++){
                dp[e+1][0][1]=1;
                for(int i=e+2;i<=n;i++){
                    for(int j=0;j<=1;j++)
                        for(int k=1;k<=6;k++){
                            if(k==1){
                            //    dp[i][j][k]=0;
                                for(int p=1;p<=6;p++)
                                    dp[i][j][k]+=dp[i-1][j^1][p];
                                dp[i][j][k]%=MOD;
                            }
                            else{
                            //    dp[i][j][k]=0;
                            //    for(int p=1;p<k;p++)
                                dp[i][j][k]+=dp[i-1][j][k-1];
                                dp[i][j][k]%=MOD;
                            }
                        }
                }
                for(int p=7-e;p<=6;p++)
                    ans-=(dp[n][1][p])*2;
                ans%=MOD;
                memset(dp,0,sizeof(dp));
            }
            printf("%d
    ",(ans%MOD+MOD)%MOD);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    039、Data Volume 之 bind mount (2019-02-28 周四)
    038、Docker 的两类存储资源(2019-02-27 周三)
    037、外部网络如何访问容器 (2019-02-26 周二)
    036、容器如何访问外部世界 (2019-02-25 周一)
    035、容器间通信的三种方式(2019-02-22 周五)
    034、理解容器之间的连通性(2019-02-21 周四)
    033、如何自定义容器网络(2019-02-20 周三)
    032、学容器必须懂bridge网络(2019-02-19 周二)
    031、none和host网络的适用场景(2019-02-18 周一)
    030、实现容器的底层技术(2019-01-25 周五)
  • 原文地址:https://www.cnblogs.com/jie-dcai/p/4886221.html
Copyright © 2011-2022 走看看