【NOIP模擬】加密+硬幣+位元戰爭
阿新 • • 發佈:2018-12-16
T1:
其實直接轉成陣列模擬是可過的。。。
正解:
程式碼:
#include <bits/stdc++.h> 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+矩陣快速冪。
有點難理解(主要是本身太菜了)。
令表示湊成的方案數,這樣最後的就可以貪心的從大到小由加法原理求得。
考慮如何求得。
由於滿足倍數關係,那麼就有:
感性理解一下就是乘法原理分步求和得到的,每步的的方案數為。
PS:取模是真的慢,建議以後都用程式碼中的寫法,能不取就不取。
程式碼:
#include <bits/stdc++.h> #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<num[i]) continue; int d=w/num[i]; B=B*(A[i]^d),w=w%num[i]; } cout<<B.a[1][1]; return 0; }
T3:
可證得最優解一定是最小生成樹形成過程中的某個狀態,於是就顯然了。
具體步驟就是做最小生成樹,考慮兩個聯通快,比較合併與不合並即可。
程式碼:
#include <bits/stdc++.h> 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<b?a:b;} inline int max(int a,int b){return a<b?b:a;} inline bool comp(const shu &a,const shu &b){return a.s<b.s;} inline int get(int v){return fa[v]==v?v:fa[v]=get(fa[v]);} signed main() { n=get_int(),m=get_int(); for(int i=1;i<=n;i++) fa[i]=i,mx[i]=get_int(),mn[i]=get_int(),sum+=(f[i]=1ll*mx[i]*mn[i]); for(int i=1;i<=m;i++) edge[i].u=get_int(),edge[i].v=get_int(),edge[i].s=get_int(); ans=min(ans,sum),sort(edge+1,edge+m+1,comp); for(int i=1;i<=m;i++) { int fa1=get(edge[i].u),fa2=get(edge[i].v); if(fa1==fa2) continue; f[fa1]+=f[fa2],sum-=f[fa1],mn[fa1]=min(mn[fa1],mn[fa2]); mx[fa1]=max(mx[fa1],mx[fa2]),mx[fa1]=max(mx[fa1],edge[i].s); sum+=(f[fa1]=min(f[fa1],1ll*mx[fa1]*mn[fa1])),fa[fa2]=fa1,ans=min(ans,sum); } cout<<ans; return 0; }