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\n",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\n",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\n",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\n",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\n",(ans%MOD+MOD)%MOD);
    }
    return 0;
}
View Code

 

posted @ 2015-10-16 20:11  chenjunjie1994  阅读(237)  评论(0编辑  收藏  举报