zoukankan      html  css  js  c++  java
  • BSUIR Open Finals

    A. Game with chocolates

    因为差值必须是$P$的幂,故首先可以$O(log n)$枚举出先手第一步所有取法,判断之后的游戏是否先手必败。

    对于判断,首先特判非法的情况,并假设$n<m$,则题意可理解成将$n$或者$m$减小至$n-P^k$,在$P$进制下可以理解为$n$某一位减$1$,且这一位在减之前不能是$0$。

    若是将$m$减小为$n-P^k$,则整个游戏都是确定的,回合数为$n$的数位之和,根据奇偶性即可判断胜负。

    但若是将$n$减小为$m-P^k$,则要求$n$和$m$位数相同且最高位相等,这意味着进行这步操作后之后不能再进行这一步操作,先手可以利用这一步来使自己必胜。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    ll P,n,m,k,a[99],b[99];
    bool check(ll n,ll m){
      if(n>m)swap(n,m);
      ll k=m-n;
      if(m/k%P==0)return 1;
      while(k%P==0)k/=P;
      if(k>1)return 1;
      if(!n)return 0;
      int la=0,lb=0;
      while(n)a[++la]=n%P,n/=P;
      while(m)b[++lb]=m%P,m/=P;
      if(la==lb&&a[la]==b[lb])return 1;
      for(int i=2;i<=la;i++)a[1]+=a[i];
      return a[1]%2;
    }
    int main(){
      scanf("%lld%lld%lld",&P,&n,&m);
      for(k=1;k<=n;k*=P)if(n-k<m)if(!check(n,n-k)){
        puts("YES");
        printf("%lld %lld",n,n-k);
        return 0;
      }
      for(k=1;k<=m;k*=P)if(m-k<n)if(!check(m-k,m)){
        puts("YES");
        printf("%lld %lld",m-k,m);
        return 0;
      }
      puts("NO");
    }
    

      

    B. Birches

    将相同的数合并,然后调和级数$O(nlog n)$枚举即可。

    #include<cstdio>
    const int N=111111;
    int n,m,k,i,j,x,l,r,f[N];long long ans;
    int main(){
    	scanf("%d%d",&n,&k);
    	while(n--){
    		scanf("%d",&x);
    		f[x]++;
    	}
    	n=100000;
    	for(i=1;i<=n;i++)if(f[i]&&k<i)
    		for(l=k;l<=n;l+=i)ans+=1LL*f[i]*f[l];
    	printf("%lld",ans);
    }
    

      

    C. Ancient CBS

    按平方数分解构造。

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<string>
    #include<ctype.h>
    #include<math.h>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    #include<bitset>
    #include<algorithm>
    #include<time.h>
    using namespace std;
    void fre() {  }
    #define MS(x, y) memset(x, y, sizeof(x))
    #define ls o<<1
    #define rs o<<1|1
    typedef long long LL;
    typedef unsigned long long UL;
    typedef unsigned int UI;
    template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
    template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
    const int N = 1e5 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
    template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
    int casenum, casei;
    int n;
    char s[(int)3e5];
    int h, t;
    void solve(int w, int st)
    {
    	for(int i = st; w >= i; ++i)
    	{
    		s[t++] = '(';
    		s[t++] = ')';
    		w -= i;
    	}
    	if(w == 0)return;
    	s[--h] = '(';
    	s[t++] = ')';
    	if(--w == 0)return;
    	solve(w, 2);
    }
    int main()
    {
    	while(~scanf("%d", &n))
    	//for(int x = 1, n = 1e9 - x; x <= 1000000; ++x, --n)
    	{
    		h = t = 1e5; s[t] = 0;
    		solve(n, 1); s[t] = 0;
    		puts(s + h);
    		/*printf("%d
    ", t - h);
    		if(t - h > 1e5)
    		{
    			puts("NO");
    			while(1);
    		}*/
    	}
    	return 0;
    }
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    D. Interactive lock

    爆搜得出方案即可。

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<string>
    #include<ctype.h>
    #include<math.h>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    #include<bitset>
    #include<algorithm>
    #include<time.h>
    using namespace std;
    void fre() {  }
    #define MS(x, y) memset(x, y, sizeof(x))
    #define ls o<<1
    #define rs o<<1|1
    typedef long long LL;
    typedef unsigned long long UL;
    typedef unsigned int UI;
    template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
    template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
    const int N = 1e5 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
    template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
    int casenum, casei;
    int n;
    int a[100] = {0, 
    2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 22, 24, 14, 18, 16, 17, 19, 20, 21, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 78, 44, 45, 46, 47, 48, 49, 50, 51, 100, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 98, 92, 97, 99, 96};
    int top = 96;
    
    /*
    bool e[N];
    int p[N];
    int v[N];
    void prime()
    {
    	int g = 0;
    	int k = 0;
    	for(int i = 2; i <= 10000; ++i)
    	{
    		if(!e[i])
    		{
    			p[++g] = i;
    			for(int j = i + i; j <= 10000; j += i)
    			{
    				e[j] = 1;
    			}
    		}
    		else
    		{
    			v[++k] = i;
    		}
    	}
    }
    */
    
    set<int>can;
    bool dfs(int g, vector<int>rst)
    {
    	if(rst.size() == 0)
    	{
    		puts("bingo");
    		printf("%d
    ", g - 1);
    		for(int i = 1; i < g; ++i)printf("%d, ", a[i]); puts("");
    		return 1;
    	}
    	set<int>::iterator it, nit;
    	for(it = can.begin(); it != can.end(); it = nit)
    	{
    		if(*it > rst.front())return 0;
    		vector<int>nxt;
    		for(auto x : rst)if(x % *it)
    		{
    			nxt.push_back(x - *it);
    		}
    		a[g] = *it;
    		nit = it; ++nit;
    		can.erase(a[g]);
    		if(dfs(g + 1, nxt))return 1;
    		can.insert(a[g]);
    	}
    	
    	/*for(auto it : can)
    	{
    		if(it > rst.front())return 0;
    		vector<int>nxt;
    		for(auto x : rst)if(x % it)
    		{
    			nxt.push_back(x - it);
    		}
    		a[g] = it;
    		can.erase(a[g]);
    		if(dfs(g + 1, nxt))return 1;
    		can.insert(a[g]);
    	}*/
    	return 0;
    }
    
    void solve()
    {
    	for(int i = 2; i <= 100; ++i)can.insert(i);
    	vector<int>rst;
    	for(int i = 100; i <= 10000; ++i)rst.push_back(i);
    	dfs(1, rst);
    }
    
    
    bool guess(int x)
    {
    	for(int i = 1; i <= top; ++i)
    	{
    		if(a[i] > x)
    		{
    			printf("%d
    ", x);
    			return 0;
    		}
    		if(x % a[i] == 0)return 1;
    		x -= a[i];
    	}
    	return 0;
    }
    
    int main()
    {
    	//prime();
    	//solve();
    	int T; scanf("%d", &T);
    	while(T--)
    	{
    		for(int i = 1; i <= top; ++i)
    		{
    			printf("%d
    ", a[i]); fflush(stdout);
    			char s[10]; scanf("%s", s);
    			if(s[0] == 'Y')break;
    		}
    	}
    	
    	/*
    	for(int i = 100; i <= 10000; ++i)
    	{
    		if(!guess(i))
    		{
    			printf("%d
    ", i);
    		}
    	}
    	puts("haha");
    	*/
    	
    	return 0;
    }
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    E. Interval divisibility

    对于每个约数计算贡献,分段求和即可。

    时间复杂度$O(sqrt{n})$。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    typedef long long ll;
    const ll P=1000000007,inv2=(P+1)/2;
    ll f(ll n){
    	n%=P;
    	return n*(n+1)%P*inv2%P;
    }
    ll cal(ll n){
    	ll ret=0;
    	for(ll i=1;i<=n;){
    		ll j=n/(n/i);
    		ret+=f(n/i)*((i+j)%P)%P*((j-i+1)%P)%P*inv2%P;
    		ret%=P;
    		i=j+1;
    	}
    	return ret;
    }
    int main(){
    	ll l,r;
    	cin>>l>>r;
    	ll ans=cal(r)-cal(l-1);
    	ans=ans%P;
    	ans=ans+P;
    	ans%=P;
    	cout<<ans;
    }
    

      

    F. A trick

    分类讨论。

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<string>
    #include<ctype.h>
    #include<math.h>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    #include<bitset>
    #include<algorithm>
    #include<time.h>
    using namespace std;
    void fre() {  }
    #define MS(x, y) memset(x, y, sizeof(x))
    #define ls o<<1
    #define rs o<<1|1
    typedef long long LL;
    typedef unsigned long long UL;
    typedef unsigned int UI;
    template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
    template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
    const int N = 1e5 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
    template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
    int casenum, casei;
    int n;
    int main()
    {
    	while(~scanf("%d", &n))
    	{
    		if(n == 0)
    		{
    			puts("-1");
    			continue;
    		}
    		int x = n;
    		int sum = 0;
    		while(x)
    		{
    			sum += x % 10;
    			x /= 10;
    		}
    		if(sum == 9 * 9)
    		{
    			puts("-1");
    		}
    		else
    		{
    			int tmp1 = sum;
    			int v1 = 0;
    			while(tmp1)
    			{
    				int can = min(tmp1, 9);
    				tmp1 -= can;
    				v1 = v1 * 10 + can;
    			}
    			
    			int tmp2 = sum;
    			int v2 = 0;
    			bool flag = 1;
    			while(tmp2)
    			{
    				int can = min(tmp2, 9 - flag);
    				flag = 0;
    				tmp2 -= can;
    				v2 = v2 * 10 + can;
    			}
    			if(v1 != n)printf("%d
    ", v1);
    			else if(v2 != n)printf("%d
    ", v2);
    			else printf("%d0
    ", v1);
    		}
    	}
    	return 0;
    }
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    G. Highest ratings year

    首先求出所有路径长度之和,并直接除以$2$,那么奇数长度的路径会算错,故再算出奇数长度的路径数即可。

    时间复杂度$O(n)$。

    #include<cstdio>
    typedef long long ll;
    const int N=100010;
    int n,i,x,y,g[N],v[N<<1],nxt[N<<1],ed;
    int cnt[2],d[N],size[N];
    ll ans;
    inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
    void dfs(int x,int y){
    	d[x]=d[y]^1;
    	cnt[d[x]]++;
    	size[x]=1;
    	for(int i=g[x];i;i=nxt[i])if(v[i]!=y){
    		dfs(v[i],x);
    		size[x]+=size[v[i]];
    		ans+=1LL*size[v[i]]*(n-size[v[i]]);
    	}
    }
    int main(){
    	scanf("%d",&n);
    	for(i=1;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
    	dfs(1,0);
    	ll odd=1LL*cnt[0]*cnt[1];
    	ans/=2;
    	ans+=odd-odd/2;
    	printf("%lld",ans);
    }
    

      

    H. Spells

    设$f[i][j]$表示考虑$S$前$i$个位置,被一路交换过来的字符是$j$能匹配成功的字符串个数,当且仅当$j$和当前字符不相同时才进行转移。

    那么转移可以写成矩阵的形式,快速幂计算。

    对于矩阵的构造,注意到每次单个字符的转移矩阵与$E$相比只有常数个位置不同,故可以利用这点在$O(26)$时间内计算矩阵乘法。

    时间复杂度$O(26sum|S|+n26^3log k)$。

    #include<cstdio>
    #include<cstring>
    #define rep(i) for(int i=0;i<N;i++)
    const int N=28,P=1000000007;
    int n,m,K,f[N],g[N][N];char s[10010];
    inline void mul(){
    	static int h[N][N];
    	rep(i)rep(j)h[i][j]=0;
    	rep(i)rep(j)if(g[i][j])rep(k)if(g[j][k])h[i][k]=(1LL*g[i][j]*g[j][k]+h[i][k])%P;
    	rep(i)rep(j)g[i][j]=h[i][j];
    }
    inline void apply(){
    	static int h[N];
    	rep(i){
    		h[i]=0;
    		rep(j)h[i]=(1LL*g[i][j]*f[j]+h[i])%P;
    	}
    	rep(i)f[i]=h[i];
    }
    inline void gao(int x){//2..27
    	//w[x][0]=1
    	//w[x][x]=P-1
    	//w[0][1]=1
    	//w[0][x]=P-1
    	//w[1][x]=P-1
    	//w[1][0]=1
    	static int h[N][N];
    	rep(i){
    		h[0][i]=g[0][i];
    		h[1][i]=g[1][i];
    		h[x][i]=g[x][i];
    	}
    	rep(i){
    		g[x][i]=(h[0][i]+g[x][i])%P;
    		g[x][i]=(1LL*(P-1)*h[x][i]+g[x][i])%P;
    		g[0][i]=(h[1][i]+g[0][i])%P;
    		g[0][i]=(1LL*(P-1)*h[x][i]+g[0][i])%P;
    		g[1][i]=(1LL*(P-1)*h[x][i]+g[1][i])%P;
    		g[1][i]=(h[0][i]+g[1][i])%P;
    	}
    }
    int main(){
    	scanf("%d",&n);
    	f[0]=1;
    	//1:sum = 2+...+27
    	while(n--){
    		scanf("%s%d",s,&K);
    		m=strlen(s);
    		rep(i)rep(j)g[i][j]=i==j;
    		for(int i=0;i<m;i++)gao(s[i]-'a'+2);
    		for(;K;K>>=1,mul())if(K&1)apply();
    	}
    	printf("%d",f[0]);
    }
    /*
    7
    a 1
    n 1
    g 1
    n 1
    g 1
    a 1
    n 1
    
    
    6
    a 1
    n 1
    g 1
    n 1
    g 1
    an 1
    */
    

      

    I. Silver table

    $n$的方案为将$n-1$的方案复制后放在上下左右四个地方,并将右上块和左下块全体加$2^k-1$,再将左下块反对角线全体加$2^k-1$得到。

    #include<cstdio>
    const int N=3222;
    int i,j,k,n,f[N][N];
    int main(){
    	f[1][1]=1;
    	for(i=2;i<=11;i++){
    		int len=1<<(i-1);
    		int hal=len/2;
    		for(j=1;j<=hal;j++)for(k=1;k<=hal;k++){
    			f[j+hal][k+hal]=f[j][k];
    			f[j+hal][k]=f[j][k+hal]=f[j][k]+len-1;
    		}
    		for(j=1;j<=hal;j++)f[j+hal][j]+=len-1;
    	}
    	scanf("%d",&n);
    	n=1<<n;
    	for(i=1;i<=n;i++){
    		for(j=1;j<=n;j++)printf("%d ",f[i][j]);
    		puts("");
    	}
    }
    

      

    J. Soldier’s life

    问题等价于找两条间距最小的平行线夹住所有点,故求出凸包后枚举每条边求出最远点即可。

    #include<cstdio>
    #include<algorithm>
    #include<set>
    #include<cmath>
    using namespace std;
    typedef double DB;
    const int N=10000;
    const DB eps = 1e-9, pi = acos(-1.0);
    DB ans=1e100;
    int n,m,i;
    struct PT{
    	DB x, y;
    	PT(DB x = 0, DB y = 0):x(x), y(y){}
    	void input(){scanf("%lf%lf", &x, &y);}
    	PT operator-(const PT&p)const{return PT(x-p.x,y-p.y);}
    	PT operator+(const PT&p)const{return PT(x+p.x,y+p.y);}
    	PT operator*(double p)const{return PT(x*p,y*p);}
    	PT operator/(double p)const{return PT(x/p,y/p);}
    	bool operator < (const PT &p) const{
    		if(fabs(x - p.x) > eps) return x < p.x; return y < p.y;}
    	void output(){printf("%.15f %.15f
    ", x, y);}
    	DB len()const{return hypot(x,y);}
    	PT rot90()const{return PT(-y,x);}
    	PT trunc(double l)const{return (*this)*l/len();}
    }a[N],b[N],c[N],fina,finb,f[N],fin[N];
    DB lim=1e100;
    DB cross(const PT&a,const PT&b){return a.x*b.y-a.y*b.x;}
    DB vect(PT p, PT p1, PT p2){
    	return (p1.x - p.x) * (p2.y - p.y) - (p1.y - p.y) * (p2.x - p.x);
    }
    int convex_hull(PT *p, int n, PT *q){
    	int i, k, m; sort(p, p + n); m = 0;
    	for(i = 0; i < n; q[m++] = p[i++])
    		while(m > 1 && vect(q[m - 2], q[m - 1], p[i]) < eps) m --;
    	k = m;
    	for(i = n - 2; i >= 0; q[m ++] = p[i --])
    		while(m > k && vect(q[m - 2], q[m - 1], p[i]) < eps) m --;
    	return --m;
    }
    void solve(PT A,PT B){
    	DB mx=0;
    	for(int i=0;i<n;i++)mx=max(mx,fabs(cross(a[i]-A,B-A)));
    	mx/=(B-A).len();
    	mx/=2;
    	if(mx<ans){
    		ans=mx;
    		fina=A;
    		finb=B;
    	}
    }
    PT line_intersection(PT a,PT b,PT p,PT q){
    	double U=cross(p-a,q-p),D=cross(b-a,q-p);
    	return a+(b-a)*(U/D);
    }
    void gao(PT A,PT B){
    	PT fa=A-B;
    	fa=fa.rot90();
    	DB ret=0;
    	for(int i=0;i<n;i++){
    		PT C=a[i],D=C+fa;
    		PT now=line_intersection(A,B,C,D);
    		DB dis=(now-C).len();
    		ret=max(ret,dis);
    		f[i]=now;
    	}
    	if(ret<lim){
    		lim=ret;
    		for(int i=0;i<n;i++)fin[i]=f[i];
    	}
    }
    int main(){
    	scanf("%d",&n);
    	for(i=0;i<n;i++)a[i].input(),b[i]=a[i];
    	m=convex_hull(b,n,c);
    	for(i=0;i<m;i++)solve(c[i],c[(i+1)%m]);
    	PT tmp=finb-fina;
    	tmp=tmp.rot90();
    	tmp=tmp.trunc(ans);
    	gao(fina+tmp,finb+tmp);
    	gao(fina-tmp,finb-tmp);
    	printf("%.10f
    ",lim);
    	for(i=0;i<n;i++)fin[i].output();
    }
    

      

    K. Casino

    DP,$f[n][m]$表示还剩$n$张红卡,$m$张黑卡的最大期望收益。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=111;
    int n,m;double f[N][N];bool v[N][N];
    double dfs(int n,int m){
    	if(!n&&!m)return 0;
    	if(v[n][m])return f[n][m];
    	v[n][m]=1;
    	double ret=0;
    	if(n)ret+=(dfs(n-1,m)+1)*n;
    	if(m)ret+=(dfs(n,m-1)-1)*m;
    	return f[n][m]=max(ret/(n+m),0.0);
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	printf("%.15f",dfs(n,m));
    }
    

      

  • 相关阅读:
    css样式初始化代码总结
    linux LVM逻辑卷的创建,扩容,缩减和删除
    MAC Jenkins安装 + Xcode + 蒲公英 + Testflight
    Linux rsyslog工具
    linux 中 Vi 和 Vim 的使用
    Zabbix实战--监控Nginx、MySQL与VM esxi主机、vSphere Client、JAVA应用
    Linux下netstat命令详解
    Debian 10上使用UFW设置防火墙
    开源网络安全检测工具——伏羲 Fuxi-Scanner
    CentOS8的web终端-cockpit,通过Cockpit管理KVM虚拟机
  • 原文地址:https://www.cnblogs.com/clrs97/p/8801350.html
Copyright © 2011-2022 走看看