1. 程式人生 > >【NOIP模擬】加密+硬幣+位元戰爭

【NOIP模擬】加密+硬幣+位元戰爭

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+矩陣快速冪。

       有點難理解(主要是本身太菜了)。

       令Av_i[i][j]表示湊成v[i]的方案數,這樣最後的w就可以貪心的從大到小由加法原理求得。

       考慮如何求得Av_i[i][j]

       由於滿足倍數關係,那麼就有:

       Av_i+=(Av_{i-1})^{v[i]/v[i-1]]}

       感性理解一下就是乘法原理分v[i]/v[i-1]]步求和得到的,每步的的方案數為Av_{i-1}

       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;
}