zoukankan      html  css  js  c++  java
  • 2021.08.29 膜你赛

    2021.08.29 膜你赛

    divide

    Description

    问是否可以将一个仅由 0~9 组成的字符串划分成两个或两个以上部分,使得

    每一部分的数字总和相等。

    Solution

    当时就是想不出 \(O(n)\) 的方法来,然后就只想到了 \(n^2\) 的方法。尽管加了优化,但还是很慢,\(O(n)\) 的真的很好写!!!

    直接枚举答案要划分的区间数,如果如果总和不能整除区间数,说明不合法,如果可以,从头开始计算是否可以划分成当前枚举的区间数,枚举从小到大,符合条件直接返回。

    Code

    /*
    * @Author: smyslenny
    * @Date:    2021.08.
    * @Title:   
    * @Main idea:
    */
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <iomanip>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <vector>
    
    #define int long long
    #define INF 0x3f3f3f3f
    #define orz cout<<"LKP AK IOI\n"
    #define MAX(a,b) (a)>(b)?(a):(b)
    #define MIN(a,b) (a)>(b)?(a):(b)
    
    using namespace std;
    const int mod=998244353;
    const int M=1e5+5;
    int n;
    int read()
    {
    	int x=0,y=1;
    	char c=getchar();
    	while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
    	while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
    	return y?x:-x;
    }
    char s[M];
    int num[M],sum[M];
    int len,js;
    void init()
    {
    
    	len=strlen(s+1),js=0;
    	for(int i=1;i<=len;i++) 
    		if(s[i]-'0'!=0) 
    			num[++js]=s[i]-'0',sum[js]=sum[js-1]+num[js];	
    }
    
    signed main()
    {
    	n=read();
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%s",s+1);
    		init();
    		int fg=0;
    		if(sum[js]==0) 
    		{
    			printf("YES\n");
    			continue;
    		}
    		for(int i=2;i<=sum[js];i++)
    		{
    			if(sum[js]%i) continue;
    			int duan=sum[js]/i,cnt=0,las=0;
    			for(int j=1;j<=js;j++)
    			{
    				if(sum[j]-sum[las]==duan) cnt++,las=j;
    				else if(sum[j]-sum[las]>duan) break;
    			}
    			if(cnt==i)
    			{
    				fg=1;
    				break;
    			}
    		}
    		if(fg==1) 
    			printf("YES\n");
    		else
    			printf("NO\n");
    	}
    	return 0;
    }
    /*
    92116543789654796748307452898565687837416361989474778740
    */
    
    

    Count

    Description

    求有多少个由 n 个带编号的点组成的无向图是连通的

    Solution

    考试的时候一直在想推公式求答案,但是方案太多了,然后公式就炸掉了。

    一种方法就是用总的连边数量减去不合法的方案数量,设 \(f_i\)​ 表示 \(i\)​ 个编号的连通图的个数,总的连边的方案数为 \(2^{C_n^2}\)​ ,不合法的为 \(\sum\limits_{j=1}^{i-1}f_i\times C_{i-1}^{j-1}\times 2^{i-j}\)​ ,所以答案为 \(f_i=2^{\frac{n\times (n-1)}{2}}-\sum\limits_{j=1}^{i-1}C_{i-1}^{j-1}\times f_j\times 2^{i-j}\)

    /*
    * @Author: smyslenny
    * @Date:    2021.08.
    * @Title:   
    * @Main idea:用合法的方案数减去不合法的方案数,总方案数是 2^{n*(n-1)/2} 
    */
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <iomanip>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <vector>
    
    #define int long long
    #define INF 0x3f3f3f3f
    #define inv 499122177
    #define orz cout<<"LKP AK IOI\n"
    #define MAX(a,b) (a)>(b)?(a):(b)
    #define MIN(a,b) (a)>(b)?(a):(b)
    
    using namespace std;
    const int mod=998244353;
    const int M=5e3+5;
    int n,Ans[M],c[M][M];
    int read()
    {
    	int x=0,y=1;
    	char c=getchar();
    	while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
    	while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
    	return y?x:-x;
    }
    int qpow(int a,int b)
    {
    	int res=1; 
    	while(b)
    	{
    		if(b&1) res=res*a%mod;
    		a=a*a%mod;
    		b>>=1;
    	}
    	return res;
    }
    			
    int f[M],g[M];//合法的方案数,不合法的方案数 
    signed main()
    {
    //	freopen("count.in","r",stdin);
    //	freopen("count.out","w",stdout); 
    	n=read();
    	for(int i=0;i<=n;i++)
    		g[i]=qpow(2,i*(i-1)/2);
    	g[0]=1,c[0][0]=1;
    	for(int i=0;i<=n;i++)
    		for(int j=0;j<=i;j++)
    		{
    			if(c[i][j]>mod) c[i][j]-=mod;
    			c[i+1][j+1]+=c[i][j];
    			c[i+1][j]+=c[i][j];	
    		}
    	f[0]=1;
    	for(int i=1;i<=n;i++)
    	{
    		int cnt=0;
    		for(int j=1;j<i;j++)
    			cnt=(cnt+c[i-1][j-1]*f[j]%mod*g[i-j]%mod)%mod;
    		f[i]=g[i]-cnt;
    		if(f[i]<0) f[i]+=mod;	
    	}
    	printf("%lld\n",f[n]);
    	return 0;
    }
    
    

    max

    Description

    有n个物品,每个物品有两个属性a[i],b[i]

    ​ 挑选出若干物品,使得这些物品a[i]的异或和<=m。问在这一限制下,b[i]的总和最大可能为多少。

    Code

    /*
    * @Author: smyslenny
    * @Date:    2021.08.
    * @Title:   
    * @Main idea:
    */
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <iomanip>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <vector>
    
    #define ll long long
    #define INF 0x3f3f3f3f
    #define orz cout<<"LKP AK IOI\n"
    #define MAX(a,b) (a)>(b)?(a):(b)
    #define MIN(a,b) (a)>(b)?(a):(b)
    
    using namespace std;
    const int mod=998244353;
    const int M=1e3+5;
    int n,mp[M],m,Ans,now;
    int read()
    {
    	int x=0,y=1;
    	char c=getchar();
    	while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
    	while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
    	return y?x:-x;
    }
    
    struct ed{
    	int u,v,w,net;
    }edge[M<<1];
    struct st{
    	int u,v,sum,lca;
    }sz[M];
    int head[M],num;
    void addedge(int u,int v)
    {
    	edge[++num].u=u;
    	edge[num].v=v;
    	edge[num].net=head[u];
    	head[u]=num;
    }
    int f[M],siz[M],dep[M],son[M],sum[M],dfn[M],js;
    
    void dfs(int u,int fa)
    {
    	sum[u]+=mp[u];
    	dep[u]=dep[fa]+1;
    	for(int i=head[u];i;i=edge[i].net)
    	{
    		int v=edge[i].v;
    		if(v==fa) continue;
    		f[v]=u;
    		sum[v]+=sum[u];
    		dfs(v,u);
    	}
    	dfn[u]=++js;
    }
    
    int top[M];
    void dfs_2(int x,int tp)
    {
    	top[x]=tp;
    	if(!son[x]) return;
    	dfs_2(son[x],tp);
    	for(int i=head[x];i;i=edge[i].net)
    	{
    		int v=edge[i].v;
    		if(v!=f[x] && v!=son[x])
    			dfs_2(v,v);
    	}
    }
    
    int lca(int x,int y)
    {
        if(dep[x]<dep[y])
            swap(x,y);
        while(dep[x]!=dep[y]) x=f[x];
        if(x!=y) x=f[x],y=f[y];
        return x;
    }
    int g[M];
    void solve(int x)
    {
    	int u=sz[x].u;
    	int Ans=0,las=0;
    	while(u!=sz[x].lca)
    	{
    		Ans+=g[u]-g[las];
    		las=u;
    		u=f[u];
    	}
    	Ans-=f[las];
    	u=sz[x].v;
    	las=0;
    	while(u!=sz[x].lca)
    	{
    		Ans+=g[u]-f[las];
    		las=u;
    		u=f[u];
    	}
    	Ans-=f[las];
    	Ans+=g[sz[x].lca];
    	f[sz[x].lca]=max(f[sz[x].lca],Ans+sz[x].sum);
    }
    void dfs(int u)
    {
    	for(int i=head[u];i;i=edge[i].net)
    	{
    		int v=edge[i].v;
    		if(v==f[u]) continue;
    		dfs(v);
    		g[u]+=f[v];
    	}
    	f[u]=g[u];
    	while(now<=m && sz[u].lca==u) 
    		solve(now++);
    }
    
    bool cmp(st a,st b)
    {
    	return dfn[a.lca]<dfn[b.lca];
    }
     
    int main()
    {
    //	freopen("max.in","r",stdin);
    //	freopen("max.out","w",stdout); 
    	n=read();
    	for(int i=1;i<=n;i++) mp[i]=read();
    	for(int i=1,u,v;i<n;i++)
    		u=read(),v=read(),addedge(u,v),addedge(v,u);
    	dfs(1,0);
    	m=read();
    	for(int i=1;i<=m;i++)
    	{
    		sz[i].u=read(),sz[i].v=read();
    		sz[i].lca=lca(sz[i].u,sz[i].v);
    		sz[i].sum=sum[sz[i].u]+sum[sz[i].v]-sum[sz[i].lca]*2+sum[f[sz[i].ca]];
    	}
    	sort(sz+1,sz+1+m,cmp);
    	now=1;
    	dfs_2(1); 
    	printf("%lld\n",f[1]);
    	return 0;
    }
    
    

    xor

    有n个物品,每个物品有两个属性a[i],b[i]

    ​ 挑选出若干物品,使得这些物品a[i]的异或和<=m。问在这一限制下,b[i]的总和最大可能为多少。

    Solution

    考试的时候忘开 long long 直接抱零,直接暴力搜索,写一个最优性剪枝就能过了。= =

    /*
    * @Author: smyslenny
    * @Date:    2021.08.
    * @Title:   
    * @Main idea:
    */
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <iomanip>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <vector>
    
    #define int long long
    #define INF 0x3f3f3f3f
    #define orz cout<<"LKP AK IOI\n"
    #define MAX(a,b) (a)>(b)?(a):(b)
    #define MIN(a,b) (a)>(b)?(a):(b)
    
    using namespace std;
    const int mod=998244353;
    const int M=1e3+5;
    int n,m,f[M],Sum[M];
    int read()
    {
    	int x=0,y=1;
    	char c=getchar();
    	while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
    	while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
    	return y?x:-x;
    }
    int a[M],b[M],Max,cnt,Ans;
    void dfs(int x,int sum)
    {
    	if(sum<=m) Ans=max(Ans,cnt);
    	if(x>n) return;
    	if(cnt+Sum[x]<Ans) return;
    	for(int i=x;i<=n;i++)
    	{
    		sum^=a[i];
    		cnt+=b[i];
    		dfs(i+1,sum);
    		sum^=a[i];
    		cnt-=b[i];
    		dfs(i+1,sum);
    		return;
    	}
    	return; 
    }
    			
    signed main()
    {
    //	freopen("xor.in","r",stdin);
    //	freopen("xor.out","w",stdout);
    	n=read(),m=read();
    	for(int i=1;i<=n;i++)
    		a[i]=read(),b[i]=read();
    	for(int i=n;i>=1;i--)
    		Sum[i]=Sum[i+1]+b[i];
    	dfs(1,0);
    	printf("%lld\n",Ans);
    	return 0;
    }
    /*
    3 5
    5 10
    4 11
    7 12
    20 285147
    384566015 438053
    1586369 69409
    742968588 264467
    356006410 370489
    232773204 506587
    40294785 486731
    630144330 5987
    654644042 197390
    100016976 279406
    37854189 337579
    448324032 722364
    46090941 694168
    17593358 888034
    354401103 514925
    827143807 239853
    367870914 105602
    457533595 439836
    280088642 770991
    747103100 78
    587000606 652347
    
    
    20 760535
    99499442 502952
    353382646 455794
    321391841 402059
    474311542 399680
    879529853 630004
    486135480 802906
    546496667 611505
    196553240 817278
    889619477 336455
    70866199 55712
    243055187 419959
    331754336 32231
    20254869 999730
    162511020 110757
    89977380 270601
    206650662 557770
    222414613 410725
    62426199 424101
    563896289 740595
    889985847 953620
    
    
    
    */
    
    本欲起身离红尘,奈何影子落人间。
  • 相关阅读:
    GDB Practice
    GCC常用命令
    使用VS2010 C#编写ActiveX控件
    [.NET] 使用 .NET Framework 開發 ActiveX Control
    VC2005开发MFC ActiveX控件
    Register DLL and OCX
    COM组件开发实践
    Java Invoke C and C++ Using JNI
    Unable to cast object of type 'System.Int32' to type 'System.String'.
    SharePoint wiki 分类获取所有的
  • 原文地址:https://www.cnblogs.com/jcgf/p/15332558.html
Copyright © 2011-2022 走看看