ccpc2024济南
<Dashboard - CCPC Jinan Test - Codeforces>
\(C\)
对于构造指令使得它能执行若干条指令这种问题,我们确实挺容易想到将其拆分为 \(+1\) 以及 \(\times 2\) 来解决。
问题就在于如何转化为这个问题。
对于这种类似于图的推进结构,最简单的永远是链。
我们发现要使栈为空,最简单的方式是从头到尾走两遍。
至此我们就有了整个问题的基础结构。
现在的问题就是在只增加一个指令的情况下完成 \(\times 2\) 以及 \(+1\) 。
\(\times 2\) 便是让其回头一次。
\(+1\) 便是让链变长一点。
#include<cstdio>
const int N=666;
struct node{
int a,b,c,d;
}t[N];
int tp,st[N];
int main(){
int n;
scanf("%d",&n);
if(n==1){
printf("1\nHALT; PUSH 127 GOTO 1");
return 0;
}
n=(n-1)/2;
while(n){
st[++tp]=n&1;
n>>=1;
}
int tot=0;
t[++tot]={1,2,1,1};
for(int i=tp-1;i>=1;i--){
t[tot]={tot,tot+1,tot,1};
tot++;
t[tot]={tot,tot+1,tot,tot};
if(st[i]){
tot++;
t[tot]={tot,tot+1,tot,tot};
}
}
printf("%d\n",tot+1);
for(int i=1;i<=tot;i++)printf("POP %d GOTO %d; PUSH %d GOTO %d\n",t[i].a,t[i].b,t[i].c,t[i].d);
printf("HALT; PUSH 127 GOTO 1");
return 0;
}
\(D\)
事实上,如果对 \(f_{u,v}=(cnt,w)\) 表示在栈顶为 \(u\) 的时候进入指令 \(v\) 后弹出 \(u\) 并进入 \(w\) 指令需要的次数,它的状态数是 \(O(n^2)\) 的。
#include<cstdio>
const int N=1055;
int n;
struct go{
int a,b,c,d;
}tt[N];
struct node{
int a,b;
}f[N][N];
int cnt=0,flag=1;
const int maxn=1024*1024+111;
const int mod=998244353;
node dfs(int u,int v){
if(++cnt>=maxn)flag=0;
if(!flag)return {0,0};
if(f[u][v].a)return f[u][v];
int top=tt[v].c,go=tt[v].d,ans=0;
if(u==0&&tt[v].a==0)return f[u][v]={1,0};
if(tt[v].a==u)return f[u][v]={1,tt[v].b};
node now1=dfs(tt[v].c,tt[v].d);
if(now1.b==0)return f[u][v]={now1.a+1,0};
else {
node now2=dfs(u,now1.b);
return f[u][v]={(now1.a+now2.a+1)%mod,now2.b};
}
}
char s[10];
int main(){
// freopen("a.in","r",stdin);
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s);
if(s[0]=='P'){
scanf("%d GOTO %d; PUSH %d GOTO %d",&tt[i].a,&tt[i].b,&tt[i].c,&tt[i].d);
}
else {
scanf(" PUSH %d GOTO %d",&tt[i].c,&tt[i].d);
}
}
int ans=dfs(0,1).a;
if(flag)printf("%d\n",ans%mod);
else puts("-1");
return 0;
}
\(H\)
此题略微抽象。
首先考虑一位会受到什么影响。
它只会受到前一位如果进位 \(+1\) 的影响。
但如果要考虑前一位是否能 \(+1\) 就又得去枚举更前面的顺序,但我们不关心他如何能 \(+1\) 。
我们仔细思考后发现,如果前一位能自由选择,那么自由选择的时候一定能通过改变若干顺序,来不改变前面的值来达到目的。
因此我们设立三种状态 \(0,1,2\) ,分别表示一定要进位,不一定要进位,能自由选择进位与否。
再套上数位 \(dp\) 常用套路即可。
#include<cstdio>
#include<cstring>
const int M=19;
int s1[M+2],s2[M+2];
long long f[M+2][2][3];
void work(){
long long x,y;
int tp1=0,tp2=0;
scanf("%lld%lld",&x,&y);
for(int i=1;i<=M;i++)s1[i]=s2[i]=0;
while(x)s1[++tp1]=x%10,x/=10;
while(y)s2[++tp2]=y%10,y/=10;
memset(f,0,sizeof f);
f[0][0][0]=1;
for(int i=1;i<=M;i++){
if(s1[i]==0){
for(int k=0;k<=s2[i];k++){
if(k<=3){
f[i][0][0]+=f[i-1][0][0];
f[i][0][0]+=f[i-1][0][1];
f[i][0][0]+=f[i-1][0][2];
}
else if(k==4){
f[i][0][0]+=f[i-1][0][0];
f[i][0][2]+=f[i-1][0][1];
f[i][0][2]+=f[i-1][0][2];
}
else {
f[i][0][1]+=f[i-1][0][0];
f[i][0][1]+=f[i-1][0][1];
f[i][0][1]+=f[i-1][0][2];
}
}
for(int k=0;k<s2[i];k++){
if(k<=3){
f[i][0][0]+=f[i-1][1][0];
f[i][0][0]+=f[i-1][1][1];
f[i][0][0]+=f[i-1][1][2];
}
else if(k==4){
f[i][0][0]+=f[i-1][1][0];
f[i][0][2]+=f[i-1][1][1];
f[i][0][2]+=f[i-1][1][2];
}
else {
f[i][0][1]+=f[i-1][1][0];
f[i][0][1]+=f[i-1][1][1];
f[i][0][1]+=f[i-1][1][2];
}
}
for(int k=s2[i]+1;k<=9;k++){
if(k<=3){
f[i][1][0]+=f[i-1][0][0];
f[i][1][0]+=f[i-1][0][1];
f[i][1][0]+=f[i-1][0][2];
}
else if(k==4){
f[i][1][0]+=f[i-1][0][0];
f[i][1][2]+=f[i-1][0][1];
f[i][1][2]+=f[i-1][0][2];
}
else {
f[i][1][1]+=f[i-1][0][0];
f[i][1][1]+=f[i-1][0][1];
f[i][1][1]+=f[i-1][0][2];
}
}
for(int k=s2[i];k<=9;k++){
if(k<=3){
f[i][1][0]+=f[i-1][1][0];
f[i][1][0]+=f[i-1][1][1];
f[i][1][0]+=f[i-1][1][2];
}
else if(k==4){
f[i][1][0]+=f[i-1][1][0];
f[i][1][2]+=f[i-1][1][1];
f[i][1][2]+=f[i-1][1][2];
}
else {
f[i][1][1]+=f[i-1][1][0];
f[i][1][1]+=f[i-1][1][1];
f[i][1][1]+=f[i-1][1][2];
}
}
}
else if(s1[i]==1){
for(int k=0;k<=s2[i];k++){
if(k==1){
f[i][0][0]+=f[i-1][0][0];
f[i][0][0]+=f[i-1][0][1];
f[i][0][0]+=f[i-1][0][2];
}
else if(k<=4){
f[i][0][0]+=f[i-1][0][1];
f[i][0][0]+=f[i-1][0][2];
}
else {
f[i][0][1]+=f[i-1][0][1];
f[i][0][1]+=f[i-1][0][2];
}
}
for(int k=0;k<s2[i];k++){
if(k==1){
f[i][0][0]+=f[i-1][1][0];
f[i][0][0]+=f[i-1][1][1];
f[i][0][0]+=f[i-1][1][2];
}
else if(k<=4){
f[i][0][0]+=f[i-1][1][1];
f[i][0][0]+=f[i-1][1][2];
}
else {
f[i][0][1]+=f[i-1][1][1];
f[i][0][1]+=f[i-1][1][2];
}
}
for(int k=s2[i]+1;k<=9;k++){
if(k==1){
f[i][1][0]+=f[i-1][0][0];
f[i][1][0]+=f[i-1][0][1];
f[i][1][0]+=f[i-1][0][2];
}
else if(k<=4){
f[i][1][0]+=f[i-1][0][1];
f[i][1][0]+=f[i-1][0][2];
}
else {
f[i][1][1]+=f[i-1][0][1];
f[i][1][1]+=f[i-1][0][2];
}
}
for(int k=s2[i];k<=9;k++){
if(k==1){
f[i][1][0]+=f[i-1][1][0];
f[i][1][0]+=f[i-1][1][1];
f[i][1][0]+=f[i-1][1][2];
}
else if(k<=4){
f[i][1][0]+=f[i-1][1][1];
f[i][1][0]+=f[i-1][1][2];
}
else {
f[i][1][1]+=f[i-1][1][1];
f[i][1][1]+=f[i-1][1][2];
}
}
}
else {
for(int k=0;k<=s2[i];k++){
if(k==s1[i]-1){
f[i][0][0]+=f[i-1][0][1];
f[i][0][0]+=f[i-1][0][2];
}
else if(k==s1[i]){
f[i][0][0]+=f[i-1][0][0];
f[i][0][0]+=f[i-1][0][2];
}
}
for(int k=0;k<s2[i];k++){
if(k==s1[i]-1){
f[i][0][0]+=f[i-1][1][1];
f[i][0][0]+=f[i-1][1][2];
}
else if(k==s1[i]){
f[i][0][0]+=f[i-1][1][0];
f[i][0][0]+=f[i-1][1][2];
}
}
for(int k=s2[i]+1;k<=9;k++){
if(k==s1[i]-1){
f[i][1][0]+=f[i-1][0][1];
f[i][1][0]+=f[i-1][0][2];
}
else if(k==s1[i]){
f[i][1][0]+=f[i-1][0][0];
f[i][1][0]+=f[i-1][0][2];
}
}
for(int k=s2[i];k<=9;k++){
if(k==s1[i]-1){
f[i][1][0]+=f[i-1][1][1];
f[i][1][0]+=f[i-1][1][2];
}
else if(k==s1[i]){
f[i][1][0]+=f[i-1][1][0];
f[i][1][0]+=f[i-1][1][2];
}
}
}
}
printf("%lld\n",f[M][0][0]);
}
int main(){
// freopen("a.in","r",stdin);
int t;
scanf("%d",&t);
while(t--)work();
return 0;
}
\(F\)
问题可以转化为需要删去的个数。
假定目前考虑的所有数最小值为 \(x\) 。
那么只有在集合里全是 \(x\) 的倍数时需要删。
当然,有可能得删多次。
直接搜索即可。
#include<cstdio>
const int N=100010,M=100000;
const int mod=998244353;
int ksm(int x,int y){
int ans=1;
while(y){
if(y&1)ans=1ll*ans*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return ans;
}
int pre[N],ipre[N];
void init(){
pre[0]=1;
for(int i=1;i<=M;i++)pre[i]=1ll*pre[i-1]*i%mod;
ipre[M]=ksm(pre[M],mod-2);
for(int i=M;i>=1;i--)ipre[i-1]=1ll*ipre[i]*i%mod;
}
int C(int x,int y){
if(y>x)return 0;
return 1ll*pre[x]*ipre[x-y]%mod*ipre[y]%mod;
}
int n,m;
int dfs(int x,int y){
if(1ll*x*y>m)return 0;
if(y==1)return 1;
int ans=C(m/x-1,y-1);
for(int k=2;k*x<=m;k++){
ans=(ans+dfs(k*x,y-1))%mod;
}
return ans;
}
int main(){
init();
scanf("%d%d",&m,&n);
int ans=0;
for(int i=1;i*n<=m;i++){
if(i*n<=m)ans=(ans+dfs(i,n))%mod;
}
printf("%d\n",(1ll*C(m,n)*n%mod+mod-ans)%mod);
return 0;
}

浙公网安备 33010602011771号