• AGC003[BCDEF]题解


    2018-12-28 有点累EF明天再写叭=v=

    2018-12-29 update EF

    B - Simplified mahjong

    可以注意到 一段连续的非0序列都可以凑出lfloorfrac{sum a_i}{2} 
floor

    就是显然%2=0的可以内部配完 然后%2=1的可以随便向两边传递这个1(就是和旁边的配对改变自己和配对的奇偶性从而使自己变成%2=0旁边变成%2=1)于是就按照0分割统计答案就行了qwq

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define inf 20021225
    #define ll long long
    #define mxn 100010
    using namespace std;
    
    ll a[mxn],n;
    
    int main()
    {
    	scanf("%lld",&n);ll ans=0;
    	for(int i=1;i<=n;i++)	scanf("%lld",&a[i]);
    	for(int i=1;i<=n;i++)
    	{
    		ll cnt=a[i];
    		while(i<n && a[i+1]!=0)	cnt+=a[i+1],i++;
    		ans+=cnt/2;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }

    C - BBuBBBlesort!

    两种操作 翻转长度为2 翻转长度为3

    我们用dis[i]表示排名第i的和它所在的初始的位置的距离

    翻转长度为2的可以改变一对的奇偶性 然后长度为3的不改变奇偶性

    然后把奇数的个数加起来/2就好啦=v=

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define inf 20021225
    #define ll long long
    #define mxn 100100
    using namespace std;
    
    int a[mxn],n,id[mxn];
    bool cmp(int x,int y)
    {
    	return a[x]<a[y];
    }
    int main()
    {
    	scanf("%d",&n);ll ans=0;
    	for(int i=1;i<=n;i++)	scanf("%d",&a[i]),id[i]=i;
    	sort(id+1,id+n+1,cmp);
    	for(int i=1;i<=n;i++)	ans+=abs(id[i]-i)&1;
    	printf("%lld
    ",ans/2);
    	return 0;
    }

    D - Anticube

    我再读错题我就是彪头[flag] = =

    读成了选择一段区间 然后思考一下午不会做= =

    看题解发现md是随便选几个

    这样的话就每个数质因数分解 然后指数全部%3变成最小表示 求一下他的补集 就是 所有指数变成(3-x)%3

    这样的话贪心选 自己或补集就可以辣 注意补集=自己只能选一个

    发现 ai 10e10 (上pollard-rho啊)

    我们可以筛一下10e10的1/3次方以内的质数 然后分解一下

    剩下的一定是一个大质数的平方或者大质数

    直接判一下就好了=v=

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<map>
    #define inf 20021225
    #define ll long long
    #define mxn 100100
    using namespace std;
    
    map<ll,int> s;
    map<ll,bool> h;
    bool isp[10100];
    ll p[1310],cnt;
    void get(int n)
    {
    	isp[1]=1;
        for(int i=2;i<=n;i++)
        {
            if(!isp[i])	p[++cnt]=i;
            for(int j=1;j<=cnt&&p[j]*i<=n;j++)
            {
                isp[p[j]*i]=1;
                if(i%p[j]==0)	break;
            }
        }
    }
    ll a[mxn],b[mxn]; int n;
    int main()
    {
    	get(10000);// printf("%d
    ",cnt);
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%lld",&a[i]);
    		ll q=a[i]; a[i]=b[i]=1ll;
    		for(int j=1;j<=cnt;j++)
    		{
    			int qwq=0;
    			if(q==1)	break;
    			if(q%p[j]==0)
    			{
    				while(q%p[j]==0)
    				{
    					q/=p[j];
    					qwq++;
    				}
    				qwq%=3;
    				if(qwq==1)	b[i]*=(ll)p[j]*p[j],a[i]*=p[j];
    				if(qwq==2)	b[i]*=p[j],a[i]*=(ll)p[j]*p[j];
    			}
    		}
    		if(q!=1)
    		{
    			ll x=(ll)sqrt(q);
    			if(x*x == q)	b[i]*=x,a[i]*=x*x;
    			else	b[i]*=q*q,a[i]*=q;
    		}
    	}
    	for(int i=1;i<=n;i++)	s[a[i]]++;
    	int	ans=0;// printf("%d
    ",ans);
    	for(int i=1;i<=n;i++)
    	{
    		if(!h[a[i]])
    		{
    			h[a[i]]=h[b[i]]=1;
    			if(a[i]==b[i])	ans++;
    			else	ans+=max(s[a[i]],s[b[i]]);
    		}
    	}
    	printf("%d
    ",ans);
    	return 0;
    }

    EF明天更!(两道神题想起来写起来都很烦= =)

    E - Sequential operations on Sequence

    神仙题做不来

    首先可以得到一个结论 a[i]>=a[i+1]的时候只有a[i+1]是有用的 那么我们可以通过单调栈来维护就可以剔除掉没有用的部分

    接下来我们来讲神仙操作

    我们将操作序列倒过来 倒着进行推导

    首先 令s = a[i+1] / a[i] 那么所有的数一定是有一个s倍的增加 然后 r=a[i+1]%a[i] 就是前r个会多出一个零头

    对于维护 我们利用两个数组 add 和 mul 分别维护个体增长和倍数级的增长

    那么我们可以通过递归来实现 solve(s,l) -> solve(s%st[pos],l*s/st[pos]) 来表示零头和倍数级

    那么我们可以通过二分来找到第一个<s的st[pos]那么就可以将这个过程优化到log

    然后注意到s每次%一个小于s的数 这样的话最多只会进行log次[类似辗转相除]

    这样的话 我们对于一次处理的复杂度是O(lgslgn)

    一共n次操作 就是O(nlgnlgs)啦

    然后处理的时候 add 是对于每一个位置的一个差分数组 那么最后就是要前缀和啦 mul就是对于每一次操作的每一个位置增长的倍数数组 那么第一次的倍数数组当然是 mul[1] 啦

    由于第一次 每一个位置 对应的都是i 每一个数只出现一次 所以就是mul整体 add就是前缀和

    最后就是 add的前缀和 + mul[1] 就是答案咯

    代码。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define inf 20021225
    #define ll long long
    #define mxn 100010
    using namespace std;
    
    ll a[mxn],stk[mxn];int tp,n,q;
    ll cnt[mxn],add[mxn],mul[mxn];
    
    int erf(int l,int r,ll x)
    {
    	int pos=r;
    	while(l<=r)
    	{
    		int mid=l+r>>1;
    		if(stk[mid] <= x)	pos=mid,l=mid+1;
    		else	r=mid-1; 
    	}
    	return pos;
    }
    
    void work(ll l,ll k,int x)
    {
    	if(!k)	return;
    	if(k<=stk[1])
    	{
    		add[1] += l;
    		add[k+1] -= l;
    		return;
    	}
    	int pos=erf(1,x,k);
    	ll tmp = k / stk[pos];
    	mul[pos] += tmp*l;
    	work(l,k%stk[pos],pos-1);
    }
    
    int main()
    {
    	scanf("%d%d",&n,&q);
    	stk[++tp] = n;
    	for(int i=1;i<=q;i++)
    	{
    		scanf("%lld",&a[i]);
    		while(tp && stk[tp] >= a[i])	tp--;
    		stk[++tp] = a[i];
    	}
    	mul[tp] = 1;
    	for(int i=tp;i>=2;i--)
    	{
    		ll tmp = stk[i]/stk[i-1];
    		ll fin = stk[i]%stk[i-1];
    		mul[i-1] += mul[i]*tmp;
    		work(mul[i],fin,i-1);
    	}
    	for(int i=1;i<=stk[1];i++)
    	{
    		add[i] += add[i-1];
    		printf("%lld
    ",mul[1]+add[i]);
    	}
    	for(int i=stk[1]+1;i<=n;i++)
    		printf("0
    ");
    	return 0;
    }

    F在路上了qwq

    F - Fraction of Fractal

    非常nb的一个题qwq(才不会说我题意理解了半天= =题意不理解的可以去loj看中文题面会好很多= =)

    看了题解才会做 简直是神仙

    我们对于一行(或一列)的两端都是黑色的计数分别为 lr ud 对所有的黑色格子计数为cnt

    然后会出现4种情况

    1.lr>0&&ud>0 这个时候必定是全部联通的 因为原图中保证了四联通 而每一个格子和上下左右是都能联通的 答案是1

    2.lr=0&&ud=0 这个时候必定是全部不连通 所以答案是 cnt^(k-1)

    3.lr>0&&ud=0 4.lr=0&&ud>0

    这两种情况是等价的 因为我们可以把其中一个旋转45°来转换成另一种情况=v=

    我们在这里只讨论 ud>0

    ud>0那么就是整个图形会有一些上下联通的块把它们连接起来 整个图形就是由一些链组成的

    这样的时候我们怎么计数呢?

    显然 链是树 所以我们可以根据森林的性质 树数=点数-边数

    这样的话我们只需要分开统计链和点就可以了

    点很好计数 每次一个黑色格子变成一个黑色联通块 是指数级增长的 就是cnt^(k-1)

    边怎么统计呢 这就用到神仙做法了

    我们再来统计一个上下接口 就是(a[i-1][j]和a[i][j])都是黑色的情况 计数为eud 这个时候它们之间是会有一条边的

    然后我们可以列出柿子 Ek = Ek-1 * cnt + eud*ud^(k-2) 边界条件就是E2=eud

    因为 每一个k-1分形里都有ud^(k-2)个联通的1阶分形然后*eud条新边就可以了=v=

    然后这个东西构造一波矩阵乘法就可以了w

    egin{bmatrix} E_{k-1} & eud*ud^{k-2} end{bmatrix} * egin{bmatrix} cnt &0 \ 1& udend{bmatrix} =egin{bmatrix} E_k&eud*ud^{k-1} end{bmatrix}

    注意边界数据 k=0 ans=1 = =

    代码。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define inf 20021225
    #define ll long long
    #define mdn 1000000007
    using namespace std;
    
    struct matrix{int a[3][3],n;};
    inline void init(matrix &a)
    {
    	memset(a.a,0,sizeof(a.a));
    }
    matrix operator *(matrix a,matrix b)
    {
    	matrix tmp; init(tmp); tmp.n=a.n;
    	//printf("%d
    ",tmp.a[2][2]);
    	for(int i=1;i<=a.n;i++)
    	for(int j=1;j<=a.n;j++)
    	for(int k=1;k<=a.n;k++)
    	tmp.a[i][j] = ((ll)tmp.a[i][j] +(ll)a.a[i][k]*b.a[k][j]%mdn)%mdn;
    	return tmp;
    }
    
    matrix ksm(matrix bs,ll mi)
    {
    	matrix tmp; tmp.n=bs.n; init(tmp);
    	for(int i=1;i<=tmp.n;i++)	tmp.a[i][i]=1;
    	while(mi)
    	{
    		if(mi&1)	tmp=tmp*bs;
    		bs=bs*bs; mi>>=1;
    	}
    	return tmp;
    }
    char mp[1100][1100];
    int ud,lr,eud,elr,cnt;
    int ksm(int bs,ll mi)
    {
    	int ans=1;
    	while(mi)
    	{
    		if(mi&1)	ans=(ll)ans*bs%mdn;
    		bs=(ll)bs*bs%mdn; mi>>=1;
    	}
    	return ans;
    }
    int main()
    {
    	int h,w;ll k;
    	scanf("%d%d%lld",&h,&w,&k);
    	if(k<=1){printf("1
    ");return 0;}
    	for(int i=1;i<=h;i++)
    	{
    		scanf("%s",mp[i]+1);
    		if(mp[i][1] == mp[i][w] && mp[i][1] =='#')	lr++;
    		for(int j=2;j<=w;j++)	if(mp[i][j] == mp[i][j-1] && mp[i][j] == '#')	elr++;
    	}
    	for(int i=2;i<=h;i++)
    		for(int j=1;j<=w;j++)	if(mp[i-1][j] == mp[i][j] && mp[i][j] == '#')	eud++;
    	for(int i=1;i<=w;i++)	if(mp[1][i] == mp[h][i] && mp[h][i] == '#')	ud++;
    	for(int i=1;i<=h;i++)	for(int j=1;j<=w;j++)	cnt+=(mp[i][j]=='#');
    	if(lr && ud)
    	{
    		printf("1
    "); return 0;
    	}
    	if(!lr && !ud)
    	{
    		printf("%d
    ",ksm(cnt,k-1)); return 0;
    	}
    	//printf("QAQ");
    	if(lr)	swap(lr,ud),swap(elr,eud); // only ud
    	matrix ans; ans.n = 2;// printf("%d %d
    ",eud,ud);
    	ans.a[1][1] = cnt; ans.a[1][2] = 0; ans.a[2][1] = 1; ans.a[2][2] = ud;
    	ans = ksm(ans,k-2);
    	int fin =(ll)ans.a[1][1]*eud%mdn + (ll)ud*eud%mdn*ans.a[2][1]%mdn;
    	fin%=mdn; int mis = ksm(cnt,k-1);// printf("%d
    ",mis);
    	//printf("%d %d %d %d
    ",ans.a[1][1],ans.a[1][2],ans.a[2][1],ans.a[2][2]);
    	printf("%d
    ",(mis-fin+mdn)%mdn);
    	return 0;
    }
  • 相关阅读:
    VC CUtilityLZW 效率还行的LZW压缩算法,随机数加密
    VC CQHashNTBuffer 牛逼的Hash表 UINT32
    VC CHashBuffer 牛逼的hash表算法,字符串查找块了100倍
    关闭Fedora防火墙
    gnome 屏幕截图
    zynq -- arm-xilinx-eabi-路径
    Fedora 14安装出现的错误
    fedora19安装后,需要安装的一些必备的软件包
    zynq -- cannot find -lxil
    Zynq -- 启动过程
  • 原文地址:https://www.cnblogs.com/hanyuweining/p/10321890.html
Copyright © 2020-2023  润新知