模拟|【NOIP模拟】加密+硬币+比特战争

T1:
其实直接转成数组模拟是可过的。。。
正解:
模拟|【NOIP模拟】加密+硬币+比特战争
文章图片

代码:

#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'); } }

T2:
DP+矩阵快速幂。
有点难理解(主要是本身太菜了)。
【模拟|【NOIP模拟】加密+硬币+比特战争】模拟|【NOIP模拟】加密+硬币+比特战争
文章图片
表示凑成模拟|【NOIP模拟】加密+硬币+比特战争
文章图片
的方案数,这样最后的模拟|【NOIP模拟】加密+硬币+比特战争
文章图片
就可以贪心的从大到小由加法原理求得。
考虑如何求得模拟|【NOIP模拟】加密+硬币+比特战争
文章图片

由于满足倍数关系,那么就有:
模拟|【NOIP模拟】加密+硬币+比特战争
文章图片

感性理解一下就是乘法原理分模拟|【NOIP模拟】加密+硬币+比特战争
文章图片
步求和得到的,每步的的方案数为模拟|【NOIP模拟】加密+硬币+比特战争
文章图片

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

T3:
可证得最优解一定是最小生成树形成过程中的某个状态,于是就显然了。
具体步骤就是做最小生成树,考虑两个联通快,比较合并与不合并即可。

代码:

#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

    推荐阅读