智推给我的ynoi,自习课想了一下就会做了,真是小清新(虽然猜了一个错结论但还是过了)
首先我们发现如果我们选的是非空集合那么限制\(1\)就是假的,因此我们可以把两个集合的交全部去掉然后剩下的部分依然是合法的
所以我们现在就是要在区间里找两个集合使得它们和相等,显然我们可以爆搜
但是区间长度太长的时候就GG了,我们考虑当数很多的时候有可能的数和骑士很多,根据抽屉原理我们容易得到一个上界\(13\)
然而我做题的时候错误地计算了上界为\(9\)竟然还过了的说……
考虑我们现在只需要考虑\(r-l+1\le 13\)的情况,那么直接经典折半搜索即可(然而我太懒了并没有写)
然后就是维护每个数的值了,容易发现我们可以直接树状数组维护每个数被立方的次数,然后利用扩展欧拉定理直接求出区间每个数的值即可
注意是扩展的因此要判断\(3^c\)和\(\varphi(v)\)的大小,这个直接取个对数即可
#include
#include
#define RI register int
#define CI const int&
using namespace std;
const int N=100005,M=1005;
int n,m,mod,a[N],b[N],opt,l,r,phi; bool flag,ct[M*10];
inline int gcd(CI x,CI y)
{
return y?gcd(y,x%y):x;
}
inline int quick_pow(int x,int p,int mod,int mul=1)
{
for (;p;p>>=1,(x*=x)%=mod) if (p&1) (mul*=x)%=mod; return mul;
}
inline int M_pow(int x,int p,int mul=1)
{
for (;p;p>>=1,x*=x) if (p&1) mul*=x; return mul;
}
class Tree_Array
{
private:
#define lowbit(x) (x&-x)
int bit[N];
public:
inline void add(RI x,CI y)
{
for (;x<=n;x+=lowbit(x)) bit[x]+=y;
}
inline int get(RI x,int ret=0)
{
for (;x;x-=lowbit(x)) ret+=bit[x]; return ret;
}
#undef lowbit
}BIT;
inline void DFS(CI nw,CI tar,int sum=0)
{
if (nw>tar) { if (ct[sum]) flag=1; ct[sum]=1; return; }
DFS(nw+1,tar,sum+b[nw]); DFS(nw+1,tar,sum);
}
inline void recover(CI nw,CI tar,int sum=0)
{
if (nw>tar) return (void)(ct[sum]=0);
recover(nw+1,tar,sum+b[nw]); recover(nw+1,tar,sum);
}
int main()
{
RI i,j; for (scanf("%d%d%d",&n,&m,&mod),i=1;i<=mod;++i)
if (gcd(i,mod)==1) ++phi; for (i=1;i<=n;++i) scanf("%d",&a[i]);
for (i=1;i<=m;++i)
{
scanf("%d%d%d",&opt,&l,&r); if (opt==2) BIT.add(l,1),BIT.add(r+1,-1); else
{
if (r-l+1>=10) { puts("Yuno"); continue; } for (j=l;j<=r;++j)
{
int c=BIT.get(j); if (log(3)*c