zoukankan      html  css  js  c++  java
  • 2021.11.9 dmy模拟赛

    前言

    突然发现如果不是写了分层代码,最好还是不要直接按照数据点判掉暴力了,万一常数小多过一个点呢?
    期望得分:(100+30+30+10=170pts)
    实际得分:(60+30+30+0=120pts)
    什么时候能不挂分...
    感觉这次时间分配不错,也可能是因为多了半个点。
    首先可喜可贺的是 (T1) 控制在了 (1.5h) 之内。虽然这期间一开始想了很多无用的结论,导致浪费了时间,但是整体也还可以,大概 (1h) 左右推出了可以矩乘的递推式(之前写了一个没法优化的 DP),后来又用 (30min) 把矩乘写上了。然而评测之后发现矩阵乘法因为取模挂了(大悲)。
    然后开 (T3),用了 (1h) 左右,推出了很多应该有用的性质,结果写完 DP 发现转移有问题,感觉可以改进,但是比较复杂,所以先放弃了。最后回来写了暴搜,有点遗憾,不过可能本来也做不出来吧。
    (T4),想了半天连样例都推不出来,按照小样例猜了个表上去,希望骗到分。
    (T2),暴力相当好写,可惜进一步就不会了。
    检查检查就到时间了。

    题解

    A poly

    矩阵快速幂。注意到 (x^{n+1}+y^{n+1}=(x+y)(x^n+y^n)-xy(x^{n-1}+y^{n-1})).

    方法和正解一模一样。。。
    草,取模的时候虽然考虑到了大部分负数取模 (+mod) 的情况,但是忘记了本身的转移矩阵里面有个负数,于是在矩阵乘法里面没有 (+mod),痛失 (40pts!!!)
    贴一下立刻就改完的代码:

    点击查看代码
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define FCC fclose(stdin),fclose(stdout)
    const int INF = 0x3f3f3f3f,N = 1e5+10,mod = 998244353; 
    inline ll read()
    {
    	ll ret=0;char ch=' ',c=getchar();
    	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
    	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
    	return ch=='-'?-ret:ret;
    }
    ll n,a,b;
    //ll f[N],mi_2[N];
    ll dp[N],mi[N];
    struct matrix 
    {
    	ll mat[3][3];
    }base,g,ans;
    void init()
    {
    	for(int i=1;i<=2;i++)
    		for(int j=1;j<=2;j++) 
    			base.mat[i][j]=(i==j);
    }
    matrix operator * (const matrix &x,const matrix &y)
    {
    	matrix ret;
    	memset(ret.mat,0,sizeof(ret.mat));
    	for(int k=1;k<=2;k++)	
    		for(int i=1;i<=2;i++)	
    			for(int j=1;j<=2;j++)
    				(ret.mat[i][j]+=x.mat[i][k]*y.mat[k][j]+mod)%=mod;
    	return ret;
    }
    matrix qpow(matrix x,ll y)
    {
    	matrix ret=base;
    	while(y)
    	{
    		if(y&1) ret=ret*x;
    		x=x*x;
    		y>>=1;
    	}
    	return ret;
    }
    void pre()
    {	
    	mi[1]=b;
    	for(ll i=3;i<=n;i++)	
    	{
    		mi[i]=mi[i-1]*b%mod;
    		dp[i]=(dp[1]*dp[i-1]%mod-b*dp[i-2]%mod+mod)%mod;
    	//	printf("dp[%lld]=%lld
    ",i,dp[i]);
    	}
    	printf("%lld
    ",dp[n]);
    }
    int main()
    {
    //	freopen("poly.in","r",stdin);
    //	freopen("poly.out","w",stdout);
    	a=read(),b=read(),n=read();
    	dp[1]=a,dp[2]=(a*a%mod-2*b+mod)%mod;
    	if(n<=1e5+1) return pre(),0;
    	init();
    	g.mat[1][1]=a,g.mat[1][2]=1;
    	g.mat[2][1]=-b,g.mat[2][2]=0;
    	ans.mat[1][1]=dp[2],ans.mat[1][2]=dp[1];
    	ans=ans*qpow(g,n-2);
    	printf("%lld
    ",ans.mat[1][1]);
    //	FCC;
    	return 0;
    	//---------------------------
    	/*
    	f[0]=a,mi_2[0]=b;
    	int lg=log2(n);
    	for(int i=1;i<=lg;i++)
    	{
    		mi_2[i]=mi_2[i-1]*mi_2[i-1]%mod;
    		f[i]=(f[i-1]*f[i-1]%mod-2*mi_2[i-1]%mod+mod)%mod;
    	//	printf("f[%d]=%lld
    ",i,f[i]);
    	}
    	for(int i=62;i>=0;i--)
    		if((1ll<<i)==n) return printf("%lld
    ",f[i]),0;
    	FCC;
    	*/
    	return 0;
    }
    /*
    4 3 1024
    797892006 888438010 66 
    */
    

    B triangle

    考虑异色角 ((a, b, c)) 的对数,满足 (ab)(bc) 异色。容易发现异色三角形对应两个异色角,同色三角形不对应异色角。计算异色角个数即可。

    看了题解真的好简单...也就一点点思维含量而已(而且以前貌似做过类似的题?),转换一下思路,统计出有多少不合法的三角形,过程中记录两种颜色边的数量即可。
    问题主要还是每太敢仔细想这道题,没想到实际上并没有那么难,再就是思维有所欠缺。(毕竟不少人都做出来了...)
    (Update:) 竞赛图三元环计数和这个思想差不多,之前 qyt 出题的时候了解过,但如今看来融会贯通的能力也需要提高。正难则反,补集转化。三元环计数

    贴一份代码:

    点击查看代码
    #include <bits/stdc++.h>
    #define fo(a) freopen(a".in","r",stdin), freopen(a".out","w",stdout)
    using namespace std;
    const int INF = 0x3f3f3f3f, N = 2e5+5, mod = 998244353;
    typedef long long ll;
    typedef unsigned long long ull;
    namespace GenHelper {
    	unsigned z1,z2,z3,z4,b,u;
    	unsigned get() {
    		b=((z1<<6)^z1)>>13;
    		z1=((z1&4294967294U)<<18)^b;
    		b=((z2<<2)^z2)>>27;
    		z2=((z2&4294967288U)<<2)^b;
    		b=((z3<<13)^z3)>>21;
    		z3=((z3&4294967280U)<<7)^b;
    		b=((z4<<3)^z4)>>12;
    		z4=((z4&4294967168U)<<13)^b;
    		return (z1^z2^z3^z4);
    	}
    	bool read() {
    		while (!u) u = get();
    		bool res = u & 1;
    		u >>= 1;
    		return res;
    	}
    	void srand(int x) {
    		z1=x;
    		z2=(~x)^0x233333333U;
    		z3=x^0x1234598766U;
    		z4=(~x)+51;
    		u = 0;
    	}
    }
    using namespace GenHelper;
    bool edge[8005][8005];
    signed main(){
    	fo("triangle");
    	ll n; int seed;
    	cin >> n >> seed;
    	srand(seed);
    	if(n < 3) return puts("0"), 0;
    	for(int i = 0 ; i < n ; i ++)
    		for(int j = i + 1 ; j < n ; j ++)
    			edge[j][i] = edge[i][j] = read();
    //	for(int i = 1 ; i <= n ; i ++)
    //		for(int j = 1 ; j <= n ; j ++)
    //			printf("%d%c",edge[i][j]," 
    "[j==n]);
    	ll ans = n*(n-1)*(n-2)/6, sum = 0;
    //	printf("ANS = %lld
    ",ans);
    	for(int i = 0 ; i < n ; i ++){
    		ll cnt1 = 0, cnt2 = 0;
    		for(int j = 0 ; j < n ; j ++) if(i != j)
    			edge[i][j] ? cnt1++ : cnt2++;
    		sum += cnt1 * cnt2;
    //		printf("%d: [%lld,%lld]
    ",i,cnt1,cnt2);
    	}
    	printf("%lld",ans-sum/2);
    	return 0;
    }
    /*
    10
    114514
    */
    

    C

    容易发现可以通过第一类操作将棋盘染色等价于初解连通。利用prim算法在O(n^2)时间求解最小生成树即可。

    本场比赛比较遗憾的题,花了大量时间投入思考,也写出了代码,但由于能力不足没能做出来高分暴力。
    或许这个时间用来思考 (T2) 更有可能做出来。
    不过此题正解确实想不到最小生成树(虽然本来也只想写 (50-80pts)),而且最后低保暴力也打完了,勉强不算太亏。

    D

    考虑记录一个局面。容易发现,可以在每个位置记录一个数 (a_i) 表示如果 Alice 最初想的数是 (i),那么 Alice 还能说几次谎。
    定义 (dp[i][j][k]) 表示数由一段 (i)(0) ,一段 (j)(1),一段 (k)(0) 构成时的答案。利用决策单调性可以做到 (O(n^3)).
    又注意到值域只有 (O(log n)),翻转值域和最后一维后复杂度为 (O(n^2log n)).
    首先我们改写游戏。
    记a[y]表示:如果A想的数是y,那么A最多还能说a[y]次谎。(a[y] < 0 说明不可能是y了) B获胜当且仅当只有一个a[y]大于等于0.
    B每次猜数 A回答之后,所有与A的回答冲突的 y 对应的 a 值减1.
    B想要用尽量少的次数将 a 值除一个位置外均变成0 .
    对a直接爆搜,期望得分20分。
    容易发现,任何时候,非负的a值一定形如:先是 u 个 0,再是 v 个 1,再是 w 个 0. 我们可以用 (dp[u][v][w]) 表示这时候还需要猜多少次,然后枚举 B 第一轮的分界位置转移。 这样的复杂度是 (O(n^4)). 期望得分40.
    但我们注意到,在某个位置之前 Alice 回答大于更优,这个位置之后 Alice 回答小于更优。 我们可以通过记录这一位置将复杂度变为 (O(n^3))。(对于固定u, v,不同w,这一位置是 单调的。因此可以线性算出来。)
    期望得分70.
    另一方面,注意到dp的值域只有 (O(logn)),且关于w单调。我们可以改写dp,写成 (F[u][v][k])表示最大的w, 满足 (dp[u][v][w] <= k).
    这样的dp状态只有 (O(n^2 * logn)) 种,且仍可用类似方法转移。
    期望得分100.

    这题做不出来感觉问题不大,毕竟博弈论涉及不多。

    总结

    • 平衡了时间分配,虽然 (T3) 翻车了,但是感觉并不是时间分配的锅。
    • 思维水平需要提高。
    • 最主要的还是不要挂分,写题的时候就应该心里预设一下哪里可能会有坑,而不是样例。
  • 相关阅读:
    HBase 高性能加入数据
    Please do not register multiple Pages in undefined.js 小程序报错的几种解决方案
    小程序跳转时传多个参数及获取
    vue项目 调用百度地图 BMap is not defined
    vue生命周期小笔记
    解决小程序背景图片在真机上不能查看的问题
    vue项目 菜单侧边栏随着右侧内容盒子的高度实时变化
    vue项目 一行js代码搞定点击图片放大缩小
    微信小程序进行地图导航使用地图功能
    小程序报错Do not have xx handler in current page的解决方法
  • 原文地址:https://www.cnblogs.com/conprour/p/15528396.html
Copyright © 2011-2022 走看看