P3277 [SCOI2011] 飞镖

大分讨。
首先有结论 \(5k\) 一下的分数除了 \(5k-1\) 都可以用两次凑出来(不打红心)
以下用 \(num\) 代表数字,\(heart\) 代表红心。

  1. \(num\ num\ num\)
    1. 前两个至少有一个不是 \(3\) 倍。
      把前两个合起来,最有一个只能是偶数,单独算。
    2. 前两个都是 \(3\) 倍。
      把一个 \(3\) 倍和一个 \(2\) 倍合起来,剩下一个 \(3\) 倍单独算。
  2. \(num\ heart\ num\)
    把两个数字合起来,红心 \(3\) 种情况(不选,\(1\) 倍,\(2\) 倍)枚举一下。
  3. \(heart\ heart\ num\)
    两个红心 \(0\)\(4\) 被枚举一下,最后一个单独算。
  4. \(num\ num\ heart\)
    两个数字合起来算,最后一个红心只能是 \(2\)
  5. \(num\ heart\ heart\)
    两个红心 \(2\)\(4\) 倍,剩一个数字单独算。
  6. \(heart\ heart\ heart\)
    三个红心,\(2\)\(6\) 倍,直接判断
    一些细节:要注意判断负数,要开 \(long\ long\),最后一个不能是 \(0\)
    时间复杂度 \(\mathcal O(T)\)

代码

/*
Luogu P3277 [SCOI2011] 飞镖
2026-03-12
*/
#include<bits/stdc++.h>
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T&x){
        x=0;char c=getchar();bool f=0;
        while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
        while(isdigit(c)) x=x*10+c-'0',c=getchar();
        f?x=-x:0;
    }
    template<typename T>
    inline void write(T x){
        if(x==0){putchar('0');return ;}
        x<0?x=-x,putchar('-'):0;short st[50],top=0;
        while(x) st[++top]=x%10,x/=10;
        while(top) putchar(st[top--]+'0');
    }
    inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
    inline void write(char c){putchar(c);}
    inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
    inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
    template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
    template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
    template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
#define int long long
int a1,b1,c1,d1,k,a2,b2,c2,d2,m,a3,b3,c3,d3,x,ans;
bool check1(int z){
    int sy=z-5*k;
    if(sy<=2*k&&sy>=2&&sy%2==0) return 1;
    if((sy+2)<=2*k) return 1;
    if(sy<=3*k&&sy>=0&&sy%3==0) return 1;
    if((sy+2)<=3*k) return 1;
    return 0;
}
bool check2(int z){
    if(z<2) return 0;
    if(z==5*k-1||z>5*k) return 0;
    return 1;
}
bool check3(int z){
    if(z<=0||z>2*k) return 0;
    return z%2==0;
}
bool check4(int z){
    if(z<0) return 0;
    if(z!=5*k-1&&z<=5*k) return 1;
    if(z<=6*k&&z%3==0) return 1;
    return 0;
}
bool check5(int z){
    if(z<0) return 0;
    if(z<=k) return 1;
    if(z<=2*k&&z%2==0) return 1;
    if(z<=3*k&&z%3==0) return 1;
    return 0;
}
void solve(){
    int add=0;
    if(check1(x)) add=1;//num num num
    if(check2(x)||check2(x-m)||check2(x-m-m)) add=1;//num heart num
    for(int i=0;i<=4;i++) if(check3(x-m*i)) add=1;//heart heart num
    if(check4(x-m-m)) add=1;//num num heart
    if(check5(x-m-m)||check5(x-m*3)||check5(x-m*4)) add=1;//heart num heart
    for(int i=2;i<=6;i++) if(x==i*m) add=1;//heart heart heart
    ans+=add;
    k=(a1*k%d1*k+b1*k+c1)%d1+20;
    m=(a2*m%d2*m+b2*m+c2)%d2+20;
    x=(a3*x%d3*x+b3*x+c3)%d3+20;
}
signed main(){
    int T;read(T);
    read(a1,b1,c1,d1,k,a2,b2,c2,d2,m,a3,b3,c3,d3,x);
    while(T--) solve();
    write(ans);
    return 0;
}
posted @ 2026-03-12 22:05  Link-Cut_Trees  阅读(3)  评论(0)    收藏  举报