B:https://ac.nowcoder.com/acm/contest/885/B
矩阵快速幂,A^n,n特别大,想到求某数sum=sum*10+s[i]-'0';
可以把n一位一位拆开,ans=ans^10 * st^(s[i]-'0'),指数相加所以分开相乘
十进制优化类似快速幂!!!
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=1e6+5;
ll x0,x1,aa,b,mod;
char n[maxn];
struct mat
{
ll a[3][3];
};
mat mm[15];
mat mul(mat p,mat q)
{
mat ans;
memset(ans.a,0,sizeof(ans.a));
for(ll i=1;i<=2;i++){
for(ll j=1;j<=2;j++){
for(ll k=1;k<=2;k++){
ans.a[i][j]=(ans.a[i][j]+p.a[i][k]*q.a[k][j])%mod;
}
}
}
return ans;
}
mat qpow(mat st,ll y)
{
mat ans;
ans.a[1][1]=1;ans.a[1][2]=0;ans.a[2][1]=0;ans.a[2][2]=1;
while(y){
if(y&1){
ans=mul(ans,st);
}
st=mul(st,st);
y>>=1;
}
return ans;
}
void fun(mat st)
{
mm[0].a[1][1]=mm[0].a[2][2]=1;
mm[0].a[1][2]=mm[0].a[2][1]=0;
for(ll i=1;i<=9;i++){
mm[i]=mul(mm[i-1],st);
}
}
int main()
{
scanf("%lld%lld%lld%lld",&x0,&x1,&aa,&b);
scanf("%s%lld",&n,&mod);
mat st,ans;
st.a[1][1]=aa;st.a[1][2]=1;st.a[2][1]=b;st.a[2][2]=0;
fun(st);
ans.a[1][1]=1;ans.a[1][2]=0;ans.a[2][1]=0;ans.a[2][2]=1;
ll len=strlen(n);
for(ll i=0;i<len;i++){
ans=qpow(ans,10);
ans=mul(ans,mm[n[i]-'0']);
}
mat res;
res.a[1][1]=x1,res.a[1][2]=x0,res.a[2][1]=0,res.a[2][2]=0;
ans=mul(res,ans);
printf("%lld\n",ans.a[1][2]);
return 0;
}
C:https://ac.nowcoder.com/acm/contest/885/C
xi=(a⋅xi−1+b)modp.给出一个值,询问等于该值的是第几个。
根据表达式退出xi项,要求的是下标,化简完n在指数位置所以用BSGS算法 ,y^x==z(mod p) 求x值。
把x换成am-b,先求出zy^b的所有值,判断y^am是否存在。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t1 = 2e3+7, t2 = 5e5+7;
unordered_map<int, int> mp;
long long n;
int x, a, b, p, q;
int pw(int w, int t)
{
int r = 1;
while(t){
if(t % 2)
r = (ll)r * w % p;
w = (ll)w * w % p;
t /= 2;
}
return r;
}
void query()
{
int v;
scanf("%d", &v);
if(a == 0){
printf("%d\n", v==x&&n>0 ? 0:(v==b&&n>1 ? 1:-1));
return;
}
if(a == 1){
v = (ll)(v - x + p) * pw(b, p-2) % p;
printf("%d\n", v < n ? v : -1);
return;
}
int y = (ll)b * pw(a-1, p-2) % p;
v = (ll)(v + y) * pw(y+x, p-2) % p;
int r = p;
for(int i = 1; i <= t1; i++){
v = (ll)v * a % p;
if(mp.count(v))
r = min(r, mp[v]-i);
}
printf("%d\n", r<p && r<n ? r : -1);
}
void get_res(){
scanf("%lld%d%d%d%d%d", &n, &x, &a, &b, &p, &q);
int s = pw(a, t1), k = 1;
mp.clear();
for(int i = 1; i <= t2; i++){
k = (ll)k * s % p;
if(!mp.count(k))
mp[k] = i * t1;
}
while(q-- > 0)
query();
}
int main()
{
int t;
scanf("%d", &t);
while(t-- > 0)
get_res();
return 0;
}
G:https://ac.nowcoder.com/acm/contest/885/G
题意:给出n,m,分别是s串,t串的长度,求s串的子序列数量,满足组成的数字比t串表示的数字大。
当子序列长度大于t串时,直接用组合数处理
当子序列长度等于t串时,dp[i][j]表示s串长度为j+1,t串长度为i+1的位置,当前可拼出等于t串的数量
当s[j]>t[i]时,表示这个字符串已经大于t串,剩余的位直接取即可,直接加到答案中。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=3005;
const ll mod=998244353;
ll c[maxn][maxn],dp[maxn][maxn];
void f()
{
for(ll i=0;i<=3000;i++){
c[i][0]=1;
for(ll j=1;j<=i;j++){
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
}
}
int main()
{
f();
ll tt,n,m;
string s,t;
cin>>tt;
while(tt--){
cin>>n>>m;
cin>>s>>t;
s='a'+s;t='a'+t;
ll ans=0;
for(ll i=1;i<=n;i++){
if(s[i]=='0') continue;
else{
for(ll j=m;j<=n-i;j++)
ans+=(c[n-i][j]%mod);
ans%=mod;
}
}
for(ll i=0;i<=n;i++){
for(ll j=0;j<=m;j++){
dp[j][i]=0;
}
}
for(ll i=0;i<=n;i++)
dp[0][i]=1;
for(ll j=1;j<=n;j++){
for(ll i=1;i<=m;i++){
dp[i][j]=dp[i][j-1];//不取这一位时,前面有的
if(s[j]==t[i]){
//可以取这一位,前面的有多少项满足条件
//可增加一位,直接加dp[i-1][j-1]
dp[i][j]=(dp[i][j]+dp[i-1][j-1])%mod;
}
else if(s[j]>t[i]){
ans+=(dp[i-1][j-1]*c[n-j][m-i])%mod;
ans%=mod;
}
}
}
cout<<ans<<endl;
}
return 0;
}
H:https://ac.nowcoder.com/acm/contest/885/H
题意:给出多组两个字母,和由它们组成的在原串中的子序列,求出原串。
简单模拟题:处理出每个字母出现的行数
原串中0-n-1的位置枚举每0-m-1个字母,并记录每一行遍历到的位置。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
int n,m;
int pos[30][15],cnt[15];
struct hang
{
int now,len;
string s;
}e[50];
string str,ans;
bool judge(int v)
{
for(int i=0;i<m-1;i++){
int id=pos[v][i];
if(e[id].now>=e[id].len||e[id].s[e[id].now]!=v+'a')
return false;
}
return true;
}
int main()
{
cin>>n>>m;
memset(cnt,0,sizeof(cnt));
memset(pos,0,sizeof(pos));
for(int i=1;i<=m*(m-1)/2;i++){
cin>>str>>e[i].len;
if(e[i].len) cin>>e[i].s;
char a=str[0],b=str[1];
e[i].now=0;
pos[a-'a'][cnt[a-'a']++]=i;
pos[b-'a'][cnt[b-'a']++]=i;
}
for(int i=0;i<n;i++){
int l=-1;
for(int j=0;j<m;j++){
if(judge(j)){
l=j;break;
}
}
if(l==-1){
cout<<"-1"<<endl;
return 0;
}
else{
for(int i=0;i<m-1;i++){
e[pos[l][i]].now++;
}
ans+='a'+l;
}
}
for(int i=1;i<=m*(m-1)/2;i++){
if(e[i].now!=e[i].len){
cout<<"-1"<<endl;
return 0;
}
}
cout<<ans<<endl;
return 0;
}
I:https://ac.nowcoder.com/acm/contest/885/I
题意:给出一个矩形,三角形的三条边长,求出是否存在这样的三角形。
1. 若一个三角形能摆在一个矩形里,总是能经过平移使得三角形至少有一个顶点和矩形
的顶点重叠,且三角形的顶点仍在矩形里;2. 重叠了三角形的某个顶点和矩形的某个顶点后,我们可以把该重叠的点当旋转轴,旋
转三角形,使得三角形有另一个点恰好在矩形的某个边上。于是我们可以枚举三角形的哪个顶点和举行的顶点重叠,以及三角形另一个位在矩形边上的 点是哪个,总是能枚举到一个完全落在矩形里面的三角形摆放位置
#include<bits/stdc++.h>
#define esp 1e-8
using namespace std;
struct node {
double x, y;
} point[3];
double w, h;
int check(double a, double b, double c, int x, int y, int z) {
point[x].x = 0.0; //点x定在原点
point[x].y = 0.0;
//点y定在贴近x轴的一侧
if(a <= w) {
point[y].x = a;
point[y].y = 0.0;
} else {
point[y].x = w;
point[y].y = sqrt(a*a - w*w);
}
double jc = acos((a*a + b*b - c*c)/(2*a*b)); //通过余弦公式算出长度为a和长度为b的边的夹角
jc += atan(point[y].y / point[y].x);
//算出长度为a的边与x轴的夹角与上一个结果加起来
// 得出长度为b的边与x轴的夹角
//已知夹角便可算出第三个点的位置
point[z].x = cos(jc) * b;
point[z].y = sin(jc) * b;
//判断 y点和x点在不在 w和h的范围内
if(point[z].x >= 0-esp && point[z].x <= w+esp && point[z].y >= 0-esp && point[z].y <= h+esp) {
printf("%.12f %.12f %.12f %.12f %.12f %.12f\n",
point[0].x, point[0].y,
point[1].x, point[1].y,
point[2].x, point[2].y);
return 1;
}
else {
return 0;
}
}
int main() {
int t;
double a, b, c;
scanf("%d", &t);
while(t--) {
scanf("%lf %lf %lf %lf %lf", &w, &h, &a, &b, &c);
if(check(a,b,c,0,1,2)) continue;
if(check(a,c,b,1,0,2)) continue;
if(check(b,a,c,0,2,1)) continue;
if(check(c,a,b,1,2,0)) continue;
if(check(b,c,a,2,0,1)) continue;
if(check(c,b,a,2,1,0)) continue;
}
}