省选模拟1
今天考试考的非常烂,不想多说......
考场上啥也没有想出来,只是零零散散的一点性质
需要集中精力,也可能需要拓宽思维,因为我思维的面有点过于狭窄了...
没啥了,没啥,就挺自卑的,挺难受的,感觉啥也不是
仅是第一场吧,后面会好起来!!
T1 ARC100F
很难,但不是很妙
分情况,讨论...
不说,但是这里写下一种\(DP\),可以在\(\mathcal{O(n)}\)时间内得到长度为\(n\)的彩虹序列有多少个
\[f_i=f_{i-1}*k+k!*(k^{i-k}-f_{i-k})
\]
每一个彩虹序列都由第一个排列出现的位置计算
前一半就是第一个排列出现的位置在\(i-k\)之前
后一半就是第一个排列出现的位置是\(i-k+1\),这样可以保证不重不漏
AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
return s*t;
}
const int mod=1e9+7;
const int N=25005;
int ksm(int x,int y){
int ret=1;
while(y){
if(y&1)ret=ret*x%mod;
x=x*x%mod;y>>=1;
}return ret;
}
int n,m,k,a[N],ll,rr;
int pos[N],sum,ans;
int f[N][405],g[N][405],sf[N][405],sg[N][405];
int jc[N],inv[N];
void spj2(){
f[0][min(ll,k-1)]=1;fo(i,0,min(ll,k-1))sf[0][i]=1;
fo(i,1,n-m){
fo(j,1,k-1)f[i][j]=(f[i-1][j-1]*(k-j+1)+sf[i-1][j])%mod;
fu(j,k-1,1)sf[i][j]=(sf[i][j+1]+f[i][j])%mod;
}
g[0][min(rr,k-1)]=1;fo(i,0,min(rr,k-1))sg[0][i]=1;
fo(i,1,n-m){
fo(j,1,k-1)g[i][j]=(g[i-1][j-1]*(k-j+1)+sg[i-1][j])%mod;
fu(j,k-1,1)sg[i][j]=(sg[i][j+1]+g[i][j])%mod;
}
fo(i,0,n-m)ans=(ans-sf[i][1]*sg[n-m-i][1]%mod+mod)%mod;
printf("%lld",ans);
}
void spj3(){
f[0][0]=sf[0][0]=1;
fo(i,1,n){
fo(j,1,k-1){
f[i][j]=(f[i-1][j-1]*(k-j+1)+sf[i-1][j])%mod;
g[i][j]=(g[i-1][j-1]*(k-j+1)+sg[i-1][j])%mod;
if(j>=m)g[i][j]=(g[i][j]+f[i][j])%mod;
}
fu(j,k-1,1){
sf[i][j]=(sf[i][j+1]+f[i][j])%mod;
sg[i][j]=(sg[i][j+1]+g[i][j])%mod;
}
}
fo(i,1,k-1)ans=(ans-g[n][i]*inv[k]%mod*jc[k-m]%mod+mod)%mod;
printf("%lld",ans);
}
signed main(){
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
n=read();k=read();m=read();
fo(i,1,m)a[i]=read();
bool fl1=false,fl2=false;
fo(i,1,min(m,k-1)){
if(!pos[a[i]])sum++;
else fl2=true;
pos[a[i]]=i;
}
jc[0]=1;fo(i,1,k)jc[i]=jc[i-1]*i%mod;
inv[0]=1;inv[k]=ksm(jc[k],mod-2);
fu(i,k-1,1)inv[i]=inv[i+1]*(i+1)%mod;
fo(i,k,m){
if(pos[a[i]]<=i-k)sum++;
else fl2=true;
pos[a[i]]=i;
if(sum==k){fl1=true;break;}
if(pos[a[i-k+1]]==i-k+1)sum--;
}
ans=(n-m+1)*ksm(k,n-m)%mod;
if(fl1){printf("%lld",ans);return 0;}
fo(i,1,m)pos[a[i]]=0;
fo(i,1,m){
if(pos[a[i]]){ll=i-1;break;}
pos[a[i]]=i;
}
fo(i,1,m)pos[a[i]]=0;
fu(i,m,1){
if(pos[a[i]]){rr=m-i;break;}
pos[a[i]]=i;
}
if(fl2){spj2();return 0;}
spj3();
return 0;
}
T2 CF1361E
这个不难,就是有点不在我的思考范围内
首先可以很快找到一个有趣点,考虑如何判断其他点
其他点的子树内一定一共有且仅有一条返祖边,并且返祖边☞的父亲一定是一个有趣点
用\(set\)启发式合并就好了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
return s*t;
}
random_device you;
mt19937 pyt(you());
int rd(int l,int r){
uniform_int_distribution<> ee(l,r);
return ee(pyt);
}
const int N=1e5+5;
int tt,T,n,m,an[N],ans,sum;
struct E{int to,nxt;}e[N*2];
int head[N],rp,dep[N],cnt;bool flag,vis[N],pd[N];
void add_edg(int x,int y){e[++rp].to=y;e[rp].nxt=head[x];head[x]=rp;}
void dfs(int x,int d){
if(dep[x])return ;
dep[x]=d;vis[x]=true;cnt++;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(!dep[y])dfs(y,d+1);
else if(vis[y])continue;
else if(dep[y])flag=false;
}
vis[x]=false;
}
bool jud(int x){
// cerr<<x<<" ";
fo(i,1,n)vis[i]=dep[i]=0;cnt=0;
flag=true;dfs(x,1);
fo(i,1,n)vis[i]=dep[i]=0;
if(flag&&cnt==n)return true;
else return false;
}
vector<int> vec[N];
multiset<int> st[N];
int sz[N];
void dfs_fi(int x,int d){
if(dep[x])return ;
dep[x]=d;vis[x]=true;cnt++;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(!dep[y]){
dfs_fi(y,d+1);
if(st[x].size()<st[y].size())swap(st[x],st[y]);
for(int i:st[y])st[x].insert(i);
}
else if(vis[y]){
st[x].insert(y);
}
else if(dep[y])flag=false;
}
vis[x]=false;
if(st[x].find(x)!=st[x].end())st[x].erase(x);
if(st[x].size()==1)vec[*st[x].begin()].push_back(x);
}
void dfs_ans(int x){
vis[x]=true;
if(pd[x]){
for(int i:vec[x])pd[i]=true;
if(x!=an[1])an[++ans]=x;
}
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(vis[y])continue;
dfs_ans(y);
}
}
signed main(){
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
T=read();tt=T;
for(tt=1;tt<=T;tt++){
fo(i,1,n)head[i]=0;rp=0;
n=read();m=read();
fo(i,1,m){
int x=read(),y=read();
add_edg(x,y);
}ans=0;
fo(i,1,1000){
int x=rd(1,n);
if(jud(x)){an[ans=1]=x;break;}
}
pd[an[1]]=true;
dfs_fi(an[1],1);dfs_ans(an[1]);
sort(an+1,an+ans+1);
fo(i,1,ans)printf("%d ",an[i]);
printf("\n");
fo(i,1,n)vis[i]=pd[i]=false,dep[i]=0,sz[i]=0,vec[i].clear(),st[i].clear();
}
return 0;
}
T3 CF1290F
很难,很妙
这里不在赘述题解,只是写一下通过这道题对数位\(dp\)的进一步理解
一般来说都是从高位到低位\(dp\),这样我们设置两个状态,是否卡上/下界
这个可以变化一下,变成从低位到高位\(dp\),那么我们原来的两个状态就要变成,是否大于上界/小于下界
这样我们可以通过高位的变化来调整这个东西
那么如果加上高低位之间是有影响的,我们知道进位比退位好写
于是我们一般采用低位到高位的写法,这个题就是这样
还有一个更加重要的东西
一般我们拆位的时候仅仅拆一个变量
而这个题,我们两个变量都要拆位,然后容易懵逼
发现两个拆位之间是有关系的,于是我们可以一起做,看贡献就好了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
return s*t;
}
const int mod=998244353;
const double pi=acos(-1.0);
const int M=505;
int n,m,ans;
int f[32][23][23][23][23][2][2];
struct XL{int x,y;}xl[6];
int ck(int x,int y,int z){
if(x^y)return x<y?1:0;
return z;
}
int dfs(int d,int zx,int fx,int zy,int fy,int dx,int dy){
if(d==30)return (!zx&&!fx&&!zy&&!fy&&!dx&&!dy);
if(~f[d][zx][fx][zy][fy][dx][dy])return f[d][zx][fx][zy][fy][dx][dy];
int &ret=f[d][zx][fx][zy][fy][dx][dy],now=(m>>d)&1;ret=0;
fo(s,0,(1<<n)-1){
int x=0,y=0;
fo(i,1,n)if((s>>i-1)&1){
if(xl[i].x>=0)fx+=xl[i].x;
else zx-=xl[i].x;
if(xl[i].y>=0)fy+=xl[i].y;
else zy-=xl[i].y;
}
if((zx&1)==(fx&1)&&(zy&1)==(fy&1)){
ret=(ret+dfs(d+1,zx>>1,fx>>1,zy>>1,fy>>1,ck(now,zx&1,dx),ck(now,zy&1,dy)))%mod;
}
fo(i,1,n)if((s>>i-1)&1){
if(xl[i].x>=0)fx-=xl[i].x;
else zx+=xl[i].x;
if(xl[i].y>=0)fy-=xl[i].y;
else zy+=xl[i].y;
}
}
return ret;
}
signed main(){
freopen("shape.in","r",stdin);
freopen("shape.out","w",stdout);
n=read();m=read();memset(f,-1,sizeof(f));
fo(i,1,n)xl[i].x=read(),xl[i].y=read();
printf("%d",(dfs(0,0,0,0,0,0,0)-1+mod)%mod);
}
QQ:2953174821