FOJ 10月赛题 FOJ2198~2204
A题。
发现是递推可以解决这道题,a[n]=6*a[n-1]-a[n-2]。因为是求和,可以通过一个三维矩阵加速整个计算过程,主要是预处理出2^k时的矩阵,可以通过这道题
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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的值。使用线段树更新,即可。具体可看代码.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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。
由于题目条件是肯定有解,所以如果“刚好”的情况只有一种,则谁说真谁说假是可以确定的。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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的情况,就可以得到结果.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }