2019 牛客多校 第五场
题目链接:https://ac.nowcoder.com/acm/contest/885#question 链接
A:
题意:签到
B:
题意:给出fn的递推关系式和n,求fn。n的范围10^(10^6)
题解:转化成矩阵连乘,这个数据量10进制优化可以过。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN=2e6+5; ll f0, f1, a, b, mod; char s[MAXN]; struct Matrix{ ll m[2][2]; }; Matrix Mul(Matrix a, Matrix b) { Matrix ans; ans.m[0][0]=0; ans.m[0][1]=0; ans.m[1][0]=0; ans.m[1][1]=0; for(int i=0; i<2; i++) for(int j=0; j<2; j++) for(int k=0; k<2; k++) ans.m[i][j]=(ans.m[i][j]+a.m[i][k]*b.m[k][j])%mod; return ans; } Matrix qpow(Matrix a, ll n) { Matrix ans; ans.m[0][0]=1; ans.m[0][1]=0; ans.m[1][0]=0; ans.m[1][1]=1; while(n) { if(n&1) ans=Mul(ans, a); a=Mul(a, a); n>>=1; } return ans; } int main() { cin>>f0>>f1>>a>>b; cin>>s>>mod; int len=strlen(s); Matrix ans, coe; ans.m[0][0]=1; ans.m[0][1]=0; ans.m[1][0]=0; ans.m[1][1]=1; coe.m[0][0]=a; coe.m[0][1]=b; coe.m[1][0]=1; coe.m[1][1]=0; for(int i=len-1; i>=0; i--) { ans=Mul(ans, qpow(coe, s[i]-'0')); coe=qpow(coe, 10); } ll res=(ans.m[1][0]*f1+ans.m[1][1]*f0)%mod; cout<<res<<endl; return 0; }
C:(未解决)
题意:给出fn的递推式,求fn=v时,n为多少。
题解:不难化简得:
不过如何求n就涉及到了BSGS算法,没搞懂,具体可参见:https://blog.csdn.net/ccsu_cat/article/details/98184813
G:
题意:给一个字符串t,一个字符串s,找出s中有多少个子序列大于字符串t
题解:划分情况,当字串长度大于t的长度时:组合数学直接求。当长度相等时:dp【i】【j】表示s中长度为i的后缀中长度为j的子序列大于t中长度为j的后缀。
此时,分s【n+1-i】和t【m+1-j】的大小关系进行讨论。注意当j的1的时候特别判定。
具体可参考:https://blog.csdn.net/qq_43857314/article/details/98212272
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN=3e3+5; const ll mod=998244353; ll dp[MAXN][MAXN], com[MAXN][MAXN]; char s[MAXN], t[MAXN]; int n, m; void make_com() { for(int i=0; i<MAXN; i++) com[i][i]=1, com[i][0]=1; for(int i=1; i<MAXN; i++) for(int j=1; j<MAXN; j++) com[i][j]=(com[i-1][j]+com[i-1][j-1])%mod; } int main() { make_com(); int T; for(cin>>T; T--; ) { cin>>n>>m; cin>>s+1>>t+1; //子序列的长度大于m时 ll ans1=0; for(int i=1; i<=n-m; i++) //起点 { if(s[i]=='0') continue; for(int j=m; j<=n-i; j++) ans1=(ans1+com[n-i][j])%mod; } //长度相等的时候 for(int i=0; i<=n; i++) for(int j=0; j<=m; j++) dp[i][j]=0; for(int i=1; i<=n; i++) for(int j=1; j<=i; j++) { if(s[i]=='0') dp[i][j]=dp[i-1][j-1]; if(j==1) { if(s[n+1-i]>t[m+1-j]) dp[i][j]=(dp[i-1][j]+com[i-1][j-1])%mod; else dp[i][j]=dp[i-1][j]; } else if(s[n+1-i]>t[m+1-j]) dp[i][j]=(dp[i-1][j]+com[i-1][j-1])%mod; else if(s[n+1-i]==t[m+1-j]) dp[i][j]=(dp[i-1][j]+dp[i-1][j-1])%mod; else dp[i][j]=dp[i-1][j]; } cout<<(ans1+dp[n][m])%mod<<endl; } return 0; }
H:
题意:用前m个小写字母构造长度为n的字符串,有(m-1)*m/2个条件,条件是:给出去除字符c1和c2后形成的串,构造一个满足条件的原串,如果没有的话,输出-1
题解:给出了去除某2个字符后的串,其实就是告诉了我们原串中部分字符的相对顺序,可以通过建图,在拓扑排序输出即可,顺序在后的是入度。(建图的时候错了很多次.)
#include <bits/stdc++.h> using namespace std; const int MAXN=1e6+5; char str[MAXN], s[MAXN]; int n, m, len, all; int cnt[30]; int in[MAXN]; vector<int> edge[MAXN], v[30], ans; void make_map() { int pre=-1; memset(cnt, 0, sizeof(cnt)); for(int i=0; i<len; i++) { int id=str[i]-'a'+1; cnt[id]++; if(v[id].size()<cnt[id]) { v[id].push_back(++all); s[all]=str[i]; } if(pre!=-1) { edge[pre].push_back(v[id][cnt[id]-1]); in[v[id][cnt[id]-1]]++; } pre=v[id][cnt[id]-1]; } } void topo() { queue<int> q; for(int i=1; i<=all; i++) if(in[i]==0) q.push(i); while(!q.empty()) { int p=q.front(); q.pop(); ans.push_back(p); for(int i=0; i<edge[p].size(); i++) { int y=edge[p][i]; in[y]--; if(in[y]==0) q.push(y); } } } int main() { cin>>n>>m; m=(m-1)*m/2; while(m--) { cin>>str>>len; if(len) cin>>str; else continue; make_map(); } topo(); if(ans.size()==n) for(int i=0; i<n; i++) printf("%c", s[ans[i]]); else printf("-1"); return 0; }
I:
题意:给出一个坐标系中给出一个矩形,和三角形的三条边长,输出满足该三角形完全在矩形内时的三个点的坐标。
题解:找出最长的边c (假设这里是c)靠在x轴上,一端点在(0, 0), 然后求另一端点如果c>x,则该边向上旋转,直到接触到wh这个矩阵的边,然后设该点为第二个端点。之后你知道了两个点,三条边,就可以求出第三个点。(额,完美的错误想法)
因为最长的边不一定是这样的(暴力ac代码验证得来的),不过那个三角形大概长成那样,可以直接暴力匹配三角形的边长判断是否满足条件也就6种情况而已。
#include <bits/stdc++.h> using namespace std; const double eps=1e-8; struct Cod{ double x, y; }ans[5]; double w, h, a, b, c; bool solve(double a, double b, double c, int x, int y, int z) { ans[x].x=0, ans[x].y=0; if(a<=w) ans[y].x=a, ans[y].y=0; else ans[y].x=w, ans[y].y=sqrt(a*a-w*w); double ang=acos((a*a+b*b-c*c)*1.0/(2.0*a*b))+atan(ans[y].y*1.0/ans[y].x); ans[z].x=b*cos(ang), ans[z].y=b*sin(ang); if(ans[z].x>-eps&&ans[z].x<w+eps && ans[z].y>-eps&&ans[z].y<h+eps) { for(int i=0; i<3; i++) printf("%.12f %.12f ", ans[i].x, ans[i].y); printf("\n"); return true; } return false; } int main() { int T; for(cin>>T; T--; ) { cin>>w>>h>>a>>b>>c; if(solve(a, b, c, 0, 1, 2)) ; else if(solve(a, c, b, 1, 0, 2)) ; else if(solve(b, a, c, 0, 2, 1)) ; else if(solve(b, c, a, 2, 0, 1)) ; else if(solve(c, a, b, 1, 2, 0)) ; else if(solve(c, b, a, 2, 1, 0)) ; // WA // if (a>=b && a>=c && (solve(a, b, c, 0, 1, 2) || solve(a, c, b, 1, 0, 2))) ; // else if(b>=a && b>=c && (solve(b, a, c, 0, 2, 1) || solve(b, c, a, 2, 0, 1))) ; // else if(c>=a && c>=b && (solve(c, a, b, 1, 2, 0) || solve(c, b, a, 2, 1, 0))) ; } return 0; }