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 }

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 }

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 }

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;
}

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;
}

时间: 2024-10-20 13:45:05

FOJ 10月赛题 FOJ2198~2204的相关文章

FOJ有奖月赛-2016年8月 Problem A Daxia &amp; Wzc&#39;s problem(找规律)

Problem A Daxia & Wzc's problem Accept: 42    Submit: 228Time Limit: 1000 mSec    Memory Limit : 32768 KB Problem Description Daxia在2016年5月期间去瑞士度蜜月,顺便拜访了Wzc,Wzc给他出了一个问题: Wzc给Daxia等差数列A(0),告诉Daxia首项a和公差d; 首先让Daxia求出数列A(0)前n项和,得到新数列A(1); 然后让Daxia求出数列A(

HDU 4975 (杭电多校 #10 1005题)A simple Gaussian elimination problem.(网络流之最大流)

题目地址:HDU 4975 对这题简直无语...本来以为这题要用什么更先进的方法,结果还是老方法,这么卡时间真的好吗....比赛的时候用了判环的方法,一直TLE..后来换了矩阵DP的方式,加了加剪枝就过了..无语了.. 代码如下: #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cstdio> #include <

EOJ2018.10 月赛

EOJ2018.10 月赛 题目一览表(Green color indicate understand and Accept) 来源 考察知识点 完成时间 A oxx 的小姐姐们 EOJ 数学+思维 2018.10.2 B 莫干山奇遇 EOJ 数学+思维 2018.10.2                 原文地址:https://www.cnblogs.com/violet-acmer/p/9739115.html

HDU 5863 cjj&#39;s string game ( 16年多校10 G 题、矩阵快速幂优化线性递推DP )

题目链接 题意 : 有种不同的字符,每种字符有无限个,要求用这k种字符构造两个长度为n的字符串a和b,使得a串和b串的最长公共部分长度恰为m,问方案数 分析 : 直觉是DP 不过当时看到 n 很大.但是 m 很小的时候 发现此题DP并不合适.于是想可能是某种组合数学的问题可以直接公式算 看到题解的我.恍然大悟.对于这种数据.可以考虑一下矩阵快速幂优化的DP 首先要想到线性递推的 DP 式子 最直观的想法就是 dp[i][j] = 到第 i 个位置为止.前面最长匹配长度为 j 的方案数 但是如果仔

FOJ有奖月赛-2016年8月(daxia专场之过四题方有奖)

6/7 这里简单写个题解,由于源代码无法查看,所以过了的题目的代码就不贴了.... 题A Problem A Daxia & Wzc's problem 题意:略 题解:这个东西显然推公式,最后推得的一个组合数学的公式与第一项和公差有关(具体公式隔太久不记得了,囧).然后注意到这个m只有一千,虽然这个i很大,但是C(a,b)的运算次数显然是由a和b较小的一个决定,所以可以优化到算一个组合数的复杂度是min(m,i). 题B Problem B Daxia & Yayamao's probl

dp FOJ 一月月赛C ytaaa

Accept: 57    Submit: 261 Time Limit: 2000 mSec    Memory Limit : 32768 KB  Problem Description Ytaaa作为一名特工执行了无数困难的任务,这一次ytaaa收到命令,需要炸毁敌人的一个工厂,为此ytaaa需要制造一批炸弹以供使用. Ytaaa使用的这种新型炸弹由若干个炸药组成,每个炸药都有它的威力值,而炸弹的威力值为组成这个炸弹的所有炸药的最大威力差的平方,即(max-min)^2,假设一个炸弹有5个

9.10 第一题 方程的解 题解

这道题当时感觉是一道几乎纯考扩展欧几里得的题,然而板子忘了--于是乎这道题被我放在第二个打. 不得不说出题人相当良心,给了大把的暴力分前20分就是c-1,20~40暴力枚举,40~60输出1.白送的60分就到手了. 然而难得是后40分,我们可以先通过扩展欧几里得先求出x最小整数解,然后首先,自己本身就无解的方程输出0就好了,其次,如果a,b中有一个为零那么就是无限解如果都为0就看c,如果异号就是无限解等等等等特判,然后就没什么了,注意要开long long,细节真心坑,而且特判的顺序也极其重要.

FOJ有奖月赛-2016年4月(校赛热身赛)

A.ABCDEFG 题意:给出一个由abcdefg(大/小)组成的字符串,计算写这些字符串要多少笔. 题解:先打一个前七个大小写字母笔画的表,之后用这个求和即可. 代码: 1 /*A*/ 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 6 int a[7]={1,1,1,2,1,2,1}; 7 int A[7]={3,2,1,2,3,3,1}; 8 9 int main() 10 { 11 int T;

课本P364 15.10第一题 作业

public class ZuoYe extends Thread { public void run(){ for(int i=1;i<=10;i++) { System.out.println("我爱你,么么哒!"+i); try { Thread.sleep(100); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } } public static void