noip模拟73[被卡常了]
noip模拟73 solutions
可惜了我的300分,一向号称代码常数小的我,被卡没了.....呜呜呜
没关系,以后考试没事就卡卡常,想睡觉的时候就卡卡常
不过今天被骂了,因为机房是我家,我觉得我一点都不懈怠
我就.....算了,不计较了
说实话吧我也不是故意的,想不出题来就想喝水,一看杯子里没有,不就接水去了嘛\(QAQ\)
然后吧喝完水还想喝,然后就不停地上厕所
好吧以后应该避免这样的事,毕竟真正考试的时候我不能接水
上厕所还要候着,考试还那么难,还是好好养成习惯吧,加油!!!
T1 小L的疑惑
这就大水题一个直接前缀和搞一搞就好了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#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--)
const int N=1e5+5;
int n,a[N],sum;
signed main(){
#ifdef oj
freopen("math.in","r",stdin);
freopen("math.out","w",stdout);
#endif
scanf("%lld",&n);
fo(i,1,n)scanf("%lld",&a[i]);
sort(a+1,a+n+1);
fo(i,1,n){
if(a[i]>sum+1)break;
sum+=a[i];
}
printf("%lld",sum+1);
}
T2 小L的数列
这个就是我被卡常卡到和暴力一个分的!!!!
气死了真的,但是后来卡过去了
直接矩阵快速幂维护指数就好了,最后统计答案。。。
AC_code
%: pragma GCC optimize(12)
#include<bits/stdc++.h>
using namespace std;
#define oj
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=205;
const int mod=998244353;
int n,m,b[N],f[N];
int ksm(int x,int y){
int ret=1;
while(y){
if(y&1)ret=1ll*ret*x%mod;
x=1ll*x*x%mod;y>>=1;
}return ret;
}
struct matrix{
int x[N][N];
matrix(){memset(x,0,sizeof(x));}
matrix operator * (matrix a)const{
matrix ret;
fo(i,1,m)fo(k,1,m){
if(!x[i][k])continue;
fo(j,1,m){
ret.x[i][j]=(ret.x[i][j]+1ll*x[i][k]*a.x[k][j])%(mod-1);
}
}
return ret;
}
}xs,ma,ans;
matrix mksm(matrix x,int y){
matrix ret;
fo(i,1,m)ret.x[i][i]=1;
while(y){
if(y&1)ret=ret*x;
x=x*x;y>>=1;
}return ret;
}
signed main(){
#ifdef oj
freopen("seq.in","r",stdin);
freopen("seq.out","w",stdout);
#endif
scanf("%d%d",&n,&m);
fo(i,1,m)scanf("%d",&b[i]);
fo(i,1,m)scanf("%d",&f[i]);
fo(i,1,m)xs.x[i][1]=b[i];
fo(i,1,m-1)xs.x[i][i+1]=1;
fo(i,1,m)ma.x[1][i]=f[m+1-i];
if(n<=m){
printf("%d",f[n]);
return 0;
}
xs=mksm(xs,n-m);
fo(i,1,1)fo(j,1,1){
ans.x[i][j]=1;
fo(k,1,m){
ans.x[i][j]=1ll*ans.x[i][j]*ksm(ma.x[i][k],xs.x[k][j])%mod;
}
}
printf("%d",ans.x[1][1]);
}
T3 连边
这个题也好水,但是我考场上脑袋瓜子坏掉了
每一个白点要么最短路经过一条边连着一个白点,要么直接连着一个黑点
所以我们先找一个最短路,然后取所有最短路中第一条边最小的就是答案了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#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--)
const int N=1e5+5;
const int inf=0x3f3f3f3f3f3f3f3f;
int n,m,bw[N],ans;
int dis[N],an[N];
int to[N<<2],nxt[N<<2],val[N<<2],head[N],rp;
void add_edg(int x,int y,int z){
to[++rp]=y;
val[rp]=z;
nxt[rp]=head[x];
head[x]=rp;
}
bool vis[N];
queue<int> q;
signed main(){
#ifdef oj
freopen("minimum.in","r",stdin);
freopen("minimum.out","w",stdout);
#endif
scanf("%lld%lld",&n,&m);
memset(dis,0x3f,sizeof(dis));
fo(i,1,n){
scanf("%lld",&bw[i]);
if(bw[i])q.push(i),dis[i]=0,vis[i]=true;
}
fo(i,1,m){
int x,y,z;scanf("%lld%lld%lld",&x,&y,&z);
add_edg(x,y,z);add_edg(y,x,z);
}
while(!q.empty()){
int x=q.front();q.pop();vis[x]=false;
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(dis[y]<dis[x]+val[i])continue;
if(dis[y]>dis[x]+val[i])an[y]=val[i];
dis[y]=dis[x]+val[i];
if(an[y]>val[i])an[y]=val[i];
if(!vis[y])q.push(y),vis[y]=true;
}
}
fo(i,1,n)if(!bw[i])ans+=an[i];
if(ans)printf("%lld",ans);
else printf("impossible");
}
T4 小L的有向图
这个状压\(DP\),我考场上竟然想到了
可是我傻不拉几的给我的复杂度加了一个\(n\)
就\(TLE\)了,后来就直接切掉了
设\(f_s\)表示,处理完\(s\)这个集合,最终得到的方案数
我们每次只需要枚举下一个点加啥
因为是拓扑序,所以所有有边指向当前点的点都必须在\(s\)集合内
所以我们只需要找到所有边中起点在\(s\)集合内,终点是当前点的个数,这些边是可选可不选的,有\(2^cnt\)种可能
AC_code
%: pragma GCC optimize(12)
#include<bits/stdc++.h>
using namespace std;
#define oj
#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--)
const int N=23;
const int M=25*25;
const int mod=998244353;
int n,m;
int edg[N][N],fr[N];
int f[1<<23],cnt[1<<23];
signed main(){
#ifdef oj
freopen("topology.in","r",stdin);
freopen("topology.out","w",stdout);
#endif
scanf("%lld%lld",&n,&m);
fo(i,1,m){
int x,y;scanf("%lld%lld",&x,&y);
edg[x][y]=true;
fr[y]|=(1<<x-1);
}
int U=(1<<n)-1;f[0]=1;
fo(s,0,U){
fo(i,1,n)if((s>>i-1)&1)cnt[s]++;
}
fo(s,0,U){
fo(i,1,n){
if((s>>i-1)&1)continue;
int tot=cnt[s&fr[i]];
f[s|(1<<i-1)]=(f[s|(1<<i-1)]+f[s]*(1ll<<tot))%mod;
}
}
printf("%lld",f[U]);
}
T5 group
插头\(DP\)我不会
T6 ZZH与计数
这题我直接跳了
T7 中国象棋
这个好秒啊,我直接去看题解了,真的想不到
设\(f_{i,j,k}\)表示,我转移到了第\(i\)行,当前有\(j\)列有\(1\)个数,有\(k\)列有\(2\)个数
这样每次直接枚举转移系数直接转移就好了,只要定义出来了就非常好做了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fxt(i,x,y) for(int i=(x);i<=(y);i++)
#define pyt(i,x,y) for(int i=(x);i>=(y);i--)
const int N=105;
const int mod=9999973;
int n,m,ans;
int f[N][N][N];
signed main(){
freopen("chess.in","r",stdin);
freopen("chess.out","w",stdout);
scanf("%lld%lld",&n,&m);
f[0][0][0]=1;
fxt(i,0,n-1){
fxt(j,0,m){
fxt(k,0,m-j){
if(!f[i][j][k])continue;
f[i+1][j][k]=(f[i+1][j][k]+f[i][j][k])%mod;
if(j>=1)f[i+1][j-1][k+1]=(f[i+1][j-1][k+1]+f[i][j][k]*j)%mod;
if(j>=2)f[i+1][j-2][k+2]=(f[i+1][j-2][k+2]+f[i][j][k]*j*(j-1)/2)%mod;
if(j+1+k<=m)f[i+1][j+1][k]=(f[i+1][j+1][k]+f[i][j][k]*(m-j-k))%mod;
if(j+2+k<=m)f[i+1][j+2][k]=(f[i+1][j+2][k]+f[i][j][k]*(m-j-k)*(m-j-k-1)/2)%mod;
if(j+1+k<=m&&j>=1)f[i+1][j][k+1]=(f[i+1][j][k+1]+f[i][j][k]*(m-j-k)*j)%mod;
}
}
}
fxt(i,0,m)fxt(j,0,m-i)ans=(ans+f[n][i][j])%mod;
printf("%lld",ans);
}
T8 奇妙的 Fibonacci
这个好像有一个结论,是我颓题解颓到的
\(f_j|f_i=j|i\)
这样就好做了,我们只需要找到一个数的约数个数和,约数平方和
这些都可以用线性筛搞定
直接看代码吧,这个我根本就口述不了
代码中\(mn_i\)表示\(i\)中最小的质因子出现的次数
\(el_i\)表示\(i\)中把最小质因子全部除掉之后的结果
AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fxt(i,x,y) for(int i=(x);i<=(y);i++)
#define pyt(i,x,y) for(int i=(x);i>=(y);i--)
const int N=1e7+5;
const int mod=1e9+7;
int n,q,a,b,c;
int pi[N],cnt,ct[N],sm[N],mn[N],el[N];
int ans1,ans2;
bool vis[N];
signed main(){
scanf("%lld",&n);
scanf("%lld%lld%lld%lld",&q,&a,&b,&c);
ct[1]=sm[1]=1;
fxt(i,2,c){
if(!vis[i]){
pi[++cnt]=i;
ct[i]=2;
sm[i]=(i*i+1)%mod;
mn[i]=el[i]=1;
}
for(int j=1;j<=cnt&&pi[j]*i<=c;j++){
vis[i*pi[j]]=true;
if(i%pi[j]==0){
mn[i*pi[j]]=mn[i]+1;
el[i*pi[j]]=el[i];
ct[i*pi[j]]=(ct[i]/(mn[i*pi[j]]))*(mn[i*pi[j]]+1);
sm[i*pi[j]]=(sm[i]*pi[j]%mod*pi[j]+sm[el[i]])%mod;
break;
}
mn[i*pi[j]]=1;
el[i*pi[j]]=i;
ct[i*pi[j]]=ct[i]<<1;
sm[i*pi[j]]=(sm[i]+sm[i]*pi[j]%mod*pi[j])%mod;
}
}
fxt(i,1,n){
ans1=(ans1+ct[q]+(q&1))%mod;
ans2=(ans2+sm[q]+(q&1)*4)%mod;
q=(q*a+b)%c+1;
}
printf("%lld\n%lld",ans1,ans2);
}