其实直接转成数组模拟是可过的。。。
正解:
代码:
#include
using namespace std;
typedef long long LL;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline LL rd() {
char ch=nc(); LL i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
inline void W(LL x) {
static int buf[50];
if(!x) {putchar('0'); return;}
if(x<0) {putchar('-'); x=-x;}
while(x) {buf[++buf[0]]=x%10; x/=10;}
while(buf[0]) {putchar(buf[buf[0]--]+'0');}
}
const LL mod=1ll<<32;
inline LL exgcd(LL a,LL b,LL &x,LL &y) {b ? (exgcd(b,a%b,y,x),y-=a/b*x) : (x=1,y=0);}
inline LL cinv(LL t) {
LL x,y;
exgcd(t,mod,x,y);
x=(x%mod+mod)%mod;
return x;
}
inline LL ksc(LL a,LL b,LL rs=0) {for(;b;b>>=1,a=(a+a)%mod) if(b&1) rs=(rs+a)%mod; return rs;}
int main() {
for(int Q=rd();Q;Q--) {
LL t=rd();
t=ksc(t,cinv((1ll<<16)+1));
LL x1=t>>22, x2=(t>>11)^(x1<<11), x3=t^(x1<<22)^(x2<<11);
x2=x2^x1; x3=x3^x2; t=(x1<<22)^(x2<<11)^x3;
t=ksc(t,cinv((1ll<<3)+1));
x1=t>>30, x2=(t>>24)^(x1<<6), x3=(t>>18)^(x1<<12)^(x2<<6);
LL x4=(t>>12)^(x1<<18)^(x2<<12)^(x3<<6), x5=(t>>6)^(x1<<24)^(x2<<18)^(x3<<12)^(x4<<6),
x6=t^(x1<<30)^(x2<<24)^(x3<<18)^(x4<<12)^(x5<<6);
x2^=x1; x3^=x2; x4^=x3; x5^=x4; x6^=x5;
t=(x1<<30)^(x2<<24)^(x3<<18)^(x4<<12)^(x5<<6)^x6;
t=ksc(t,cinv((1ll<<10)+1));
W(t); putchar('\n');
}
}
DP+矩阵快速幂。
有点难理解(主要是本身太菜了)。
令表示凑成
的方案数,这样最后的
就可以贪心的从大到小由加法原理求得。
考虑如何求得。
由于满足倍数关系,那么就有:
感性理解一下就是乘法原理分步求和得到的,每步的的方案数为
。
PS:取模是真的慢,建议以后都用代码中的写法,能不取就不取。
代码:
#include
#define int long long
using namespace std;
const int Max=55;
const int mod=1e9+7;
int n,w,num[Max];
inline int add(int a,int b){return (a+b)>=mod?(a+b)%mod:a+b;}
inline int mul(int a,int b){return (a*b)>=mod?(a*b)%mod:a*b;}
struct matrix{
int a[Max][Max];
matrix(int t=0){
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++) a[i][i]=t;
}
friend inline matrix operator +(const matrix &a,const matrix &b){
matrix c(0);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
c.a[i][j]=add(a.a[i][j],b.a[i][j]);
return c;
}
friend inline matrix operator *(const matrix &a,const matrix &b){
matrix c(0);
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
for(int j=1;j<=n;j++)
c.a[i][j]=add(c.a[i][j],mul(a.a[i][k],b.a[k][j]));
return c;
}
friend inline matrix operator ^(matrix a,int b){
matrix c(1);
while(b)
{
if(b&1) c=c*a;
b>>=1,a=a*a;
}
return c;
}
}A[Max];
inline int get_int()
{
int x=0;char c;
for(c=getchar();(!isdigit(c));c=getchar());
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^48);
return x;
}
inline void init(int p)
{
for(int i=1;i<=p;i++) A[p].a[p][i]=1;
if(p>1) A[p]=A[p]+(A[p-1]^(num[p]/num[p-1]));
}
signed main()
{
n=get_int(),w=get_int();
for(int i=1;i<=n;i++) num[i]=get_int();
for(int i=1;i<=n;i++) init(i);
matrix B(0);
for(int i=1;i<=n;i++) B.a[1][i]=1;
for(int i=n;i>=1;i--)
{
if(w
可证得最优解一定是最小生成树形成过程中的某个状态,于是就显然了。
具体步骤就是做最小生成树,考虑两个联通快,比较合并与不合并即可。
代码:
#include
using namespace std;
const int Max=100010;
int n,m;
long long ans=1e18,sum,f[Max];
int fa[Max],num[Max],mn[Max],mx[Max],u[Max],v[Max],s[Max];
struct shu{int u,v,s;}edge[Max<<1];
inline int get_int()
{
int x=0;char c;
for(c=getchar();(!isdigit(c));c=getchar());
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^48);
return x;
}
inline int min(int a,int b){return a