A
签到题
/*简化版*/
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
const int N=1e5+10;
int main()
{
int _;
cin>>_;
while(_--)
{
ll n;
scanf("%lld",&n);
ll t=n;
while(t--) printf("%lld",n);
puts("");
}
}
B 求一个递推式
普通矩阵快速幂是二进制,这里可以化为十进制
化成十进制递推即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=2;
ll mod;
struct Matrix
{
ll mat[MAXN][MAXN];
Matrix() {}
Matrix operator*(Matrix const &b)const
{
Matrix res;
memset(res.mat, 0, sizeof(res.mat));
for (int i = 0 ;i < MAXN; i++)
for (int j = 0; j < MAXN; j++)
for (int k = 0; k < MAXN; k++)
res.mat[i][j] = (res.mat[i][j]+this->mat[i][k] * b.mat[k][j])%mod;
return res;
}
};
Matrix base,fi;
ll x0,x1,a,b;
int len;
const int N=1e6+10;
char s[N];
void gao() {
int p = len;
while (s[p] == '0') p--;
s[p]--;
for (int i = p + 1; i <= len; i++)
s[i] = '9';
}
int main()
{
cin>>x0>>x1>>a>>b;
cin>>s+1>>mod;
base.mat[0][0] = a;
base.mat[0][1] = b;
base.mat[1][0] = 1;
base.mat[1][1] = 0;
fi.mat[0][0]=x1;
fi.mat[1][0]=x0;
len=strlen(s+1);
gao();
Matrix res;
memset(res.mat, 0, sizeof(res.mat));
for (int i = 0; i < MAXN; i++)
res.mat[i][i] = 1;
for(int i=len;i>=1;--i)
{
if(s[i]>'0')
{
int d=s[i]-'0';
while(d--) res = res*base;
}
int d=9;
Matrix tmp=base;
while(d--) base = base*tmp;
}
res=res*fi;
printf("%lld\n", res.mat[0][0]);
return 0;
}
C generator 2 BSGS
什么是bsgs?
BSGS一般是求下面这个公式:,a、b、p已知,求n。
将n分解为那么原公式可以化简为
,模数已经省略。此时我们可以枚举x从1到sqrt(p)用一个map保存左边的数。
接着枚举y从1到sqrt(p),把右边的值算出来,从map里查找即可。
那么这个题怎么用bsgs呢?
题目公式:.
求前几项可以得到
得到一般公式,后面这一项就是等比公式的求和公式
继续化简成这种形式。
右边这一堆当成一个变量v就可以了
注意这里的n得这样化简:,原因不详。因为学习来自:https://blog.csdn.net/ccsu_cat/article/details/98184813#commentBox
那么得到,枚举x从1到1e6预处理一下,接着每次询问,暴力枚举y就可以得到答案了。
还得注意的是,a=0,a=1的情况需要特殊处理。。
自己的代码一直超时,
【自己的代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int xn,x0,a,b,p;
ll n;
ll powmod(ll a,ll b) {ll res=1;a%=p;
for(;b;b>>=1){if(b&1)res=1ll*res*a%p;a=1ll*a*a%p;}return res%p;}
unordered_map<int,int>mp;
const int t1=1000;
ll ans;
int q,inv,txt,tmp,y;
int main()
{
int _;
scanf("%d",&_);
while(_--)
{
scanf("%lld%d%d%d%d",&n,&x0,&a,&b,&p);
mp.clear();
tmp=1;
y=powmod(a,t1);
for(int x=1;x<=1e6;++x)
{
tmp=1ll*y*tmp%p;
if(!mp.count(tmp)) mp[tmp]=x*t1;
}
scanf("%d",&q);
inv=powmod((1ll*x0*(1-a)-b)%p,(p-2));
txt=powmod(b,p-2);
while(q--)
{
scanf("%d",&xn);
ans=0x3f3f3f3f3f3f3f3f;
if(a==0)
{
//xn=b x0=x0
if(xn==x0) printf("0\n");
else if(xn==b) printf("1\n");
else printf("-1\n");
continue;
}
else if(a==1)
{
//xn-x0/b xn=x0+b
ans=1ll*(xn-x0+p)*txt%p;
if(ans<n) printf("%lld\n",ans);
else printf("-1\n");
continue;
}
tmp=a;
int V=a;
for(int t2=0;t2<=1000;++t2)
{
if(mp[V]) ans=min(ans,1ll*mp[V]-t2);
V=(1ll*xn*(1-a)-b)%p*inv%p*tmp%p;
tmp=1ll*tmp*a%p;
}
if(ans==0x3f3f3f3f3f3f3f3f||ans>=n) printf("-1\n");
else printf("%lld\n",ans);
}
}
return 0;
}
【别人的AC代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int mod;
int t1=1001,t2=1e6;
ll powmod(ll a,ll b) {ll res=1;a%=mod;
assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
unordered_map<int,int>mp;
int main()
{
int T;
scanf("%d",&T);
while(T--){
mp.clear();
ll n;int x0,a,b,Q;
scanf("%lld%d%d%d%d%d",&n,&x0,&a,&b,&mod,&Q);
ll s = powmod(a,t1);
int x = 1;
for(int i=1;i<=t2;++i){
x = 1ll*x*s%mod;
if(!mp.count(x)) mp[x] = i*t1;
}
int mu = (b+1ll*a*x0%mod-x0+mod)%mod;
int inv = powmod(mu,mod-2);
while(Q--){
ll v;
scanf("%lld",&v);
if(!a){
if(v==x0) puts("0");
else if(v==b) puts("1");
else puts("-1");
continue;
}
if(a==1){
ll ans = (v-x0+mod)%mod*(powmod(b,mod-2))%mod;
if(ans<n) printf("%lld\n",ans);
else puts("-1");
continue;
}
int ans=mod+1;
v = (1ll*v*(a-1)%mod+b)*inv%mod;
int y=v;
for(int i=0;i<=t1;++i){
if(mp.count(y)) ans=min(ans,mp[y]-i);
y=1ll*y*a%mod;
}
if(ans==mod+1||1ll*ans>=n) puts("-1");
else printf("%d\n",ans);
}
}
}
G dp
统计s串中比t串大的子序列个数。
做法:设dp[i][j]为前i位选取j个数时的合法个数,f[i][j]为前i个数,选取j个数刚好等于t串时的个数。
二维枚举一下,s串和t串,若s[i]>t[j],那么
解析一下:当前数可取,由上一层合法且少一个数的d[i-1][j-1]转移一次,以及从上一层相等的且少一个数的f[i-1][j-1]转移一次,以及上层已有合法d[i-1][j]转移一次
若若s[i]==t[j]那么同理
只能由上一层合法且少一个数的d[i-1][j-1]转移一次,以及上层已有合法d[i-1][j]转移一次
初始值f[i][0]=1
【代码】
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e3+10;
ll c[N][N];
char s[N],t[N];
ll dp[N][N],f[N][N];
const ll mod=998244353;
void init(){
c[0][0] = 1;
for (int i = 1; i <= 3000; i++) {
c[i][0] = c[i][i] = 1;
for (int j = 1; j < i; j++)
c[i][j]=(c[i - 1][j - 1] + c[i - 1][j])%mod;
}
}
int main()
{
init();
int _;cin>>_;
while(_--)
{
int n,m;
cin>>n>>m;
scanf("%s%s",s+1,t+1);
for(int i=0;i<=n+1;++i)
for(int j=0;j<=m+1;++j) dp[i][j]=f[i][j]=0;
for(int i=0;i<=n;++i) f[i][0]=1;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
dp[i][j]=(dp[i][j]+dp[i-1][j])%mod,
f[i][j]=f[i-1][j],
dp[i][j]=(dp[i][j]+dp[i-1][j-1])%mod;
for(int j=1;j<=min(i,m);++j)
{
if(s[i]>t[j]) dp[i][j]=(dp[i][j]+f[i-1][j-1])%mod;
else if(s[i]==t[j]) f[i][j]=(f[i][j]+f[i-1][j-1])%mod;
}
}
ll ans=0;
for(int i=1;i<=n;++i)
{
if(s[i]!='0')
for(int j=m;j<=n-i;++j)
{
ans=(ans+c[n-i][j])%mod;
}
}
printf("%lld\n",(dp[n][m]+ans)%mod);
}
return 0;
}
/*
2 2
24
13
*/
H题
询问字符串,问能否构造这么一个字符串。
拓扑排序的经典问题了。当时不会写~~丢人
【代码】
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10,M=100;
vector<int>G[N],val[N];
char s[N],t[N];
map<int,char>ma;
vector<int>a;
vector<char>ans;
int vis[30],vs[N],du[N],n,m;
void tobo()
{
int res=0;
int tt=n;
while(1)
{
int tmp=-1;
for(int i=0;i<a.size();++i)
{
if(du[a[i]]==0){
tmp=a[i];
break;
}
}
if(tmp==-1) break;
ans.push_back(ma[tmp]);
res++;
du[tmp]=-1;
for(int i=0;i<G[tmp].size();++i) du[G[tmp][i]]--;
}
if(ans.size()==n)
for(int i=0;i<ans.size();++i) printf("%c",ans[i]);
else printf("-1");
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m*(m-1)/2;++i)
{
int q;
cin>>s+1>>q; if(q>0) cin>>t+1;
memset(vis,0,sizeof(vis));
int pre=-1;
for(int j=1;j<=q;++j)
{
vis[t[j]-'a']++;
int num=vis[t[j]-'a'];
int cnt=num*M+t[j]-'a';
ma[cnt]=t[j];
a.push_back(cnt);
if(pre==-1) {
pre=cnt;continue;
}
du[cnt]++;
G[pre].push_back(cnt);
pre=cnt;
}
}
sort(a.begin(),a.end());
a.erase(unique(a.begin(),a.end()),a.end());
if(a.size()!=n) printf("-1");
else tobo();
return 0;
}
F 题神仙题
先献上题解的说法:
求最大独立集数量会,可这个输出这个集合是什么操作?
拿别人代码欣赏欣赏,一天过去了,还是没看懂,先贴上当板子用吧(凄惨~~~)一天只补一个题的凄惨。。。。。
写了一些解析
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=5005;
const int mod=3007;
int a[maxn];
int match[maxn],match2[maxn];
bool mp[maxn][maxn];
vector<int>V;
int vis[maxn];
int mark[maxn];
int n;
struct Edge{
int from,nex,to;
}edge[maxn*2005];
int head[maxn],cnt;
inline void addedge(int u,int v){
edge[cnt]={u,head[u],v};
head[u]=cnt++;
}
bool dfs(int u){//匹配点
vis[u]=1;
for(int i=head[u];~i;i=edge[i].nex){
int v=edge[i].to;
if(!vis[v]){
vis[v]=true;
if(match[v]==-1||dfs(match[v])){
match[v]=u;
match2[u]=v;//被匹配过的点
return true;
}
}
}
return false;
}
void dfs2(int u){//染色
for(int i=head[u];~i;i=edge[i].nex){
int v=edge[i].to;
if(mark[v]!=-1)continue;
mark[v]=mark[u]^1;
dfs2(v);
}
}
int cal(int x,int y)
{
int num=0;
while(x||y)
{
if(x%2!=y%2) num++;
x>>=1,y>>=1;
}
return num;
}
int main()
{
memset(head,-1,sizeof head);
ios::sync_with_stdio(false);
for(int i=0;i<=30;i++){
V.push_back(1<<i);
}
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+n+1);
// memset(viss,-1,sizeof viss);
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
/*int num=cal(a[i],a[j]);//这种写法会超时,亲身测试
if(num==1)
{
addedge(i,j);
addedge(j,i);
} */
if(*lower_bound(V.begin(),V.end(),a[i]^a[j])==(a[i]^a[j])){
addedge(i,j);
addedge(j,i);
}
}
}
memset(mark,-1,sizeof mark);
for(int i=1;i<=n;i++){//染色操作,分成两部分,方便接下来的操作
//不用输出路径的话无需染色操作
if(mark[i]==-1){
mark[i]=0;
dfs2(i);
}
}
int sum=0;
memset(match,-1,sizeof match);
for(int i=1;i<=n;i++){//进行最大匹配操作,并记录了匹配的方案
//match2记录mark为0,的 match2记录mark为1的
if(mark[i]!=0)continue;
memset(vis,0,sizeof vis);
if(dfs(i)) sum++;//0在左边出发找匹配点,从0一边出发找
}
cout<<n-sum<<endl;//最大团的数量等于所有的点减去最大匹配数
memset(vis,0,sizeof vis);
for(int i=1;i<=n;i++){
if(mark[i]==0&&(!match2[i])){//在左边为0,且未匹配
//???这里就看不懂了
//最后来一遍dfs二分图匹配什么意思
dfs(i);
}
}
for(int i=1;i<=n;i++){
if((mark[i]==0&&vis[i]==0)||(mark[i]==1&&vis[i]==1))continue;
///这样的输出方式也是不懂是什么鬼什么鬼么鬼鬼(暴怒!!)
cout<<a[i]<<" ";
}
cout<<endl;
return 0;
}