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) 翻车了,但是感觉并不是时间分配的锅。
    • 思维水平需要提高。
    • 最主要的还是不要挂分,写题的时候就应该心里预设一下哪里可能会有坑,而不是样例。
  • 相关阅读:
    sshd
    eclipse运行报java.lang.OutOfMemoryError: PermGen space解决方法
    项目之间依赖
    shell-
    部署记录
    mysql index使用
    GitHub上搭建私人hexo博客操作教程
    关于Vue实例的生命周期(2)
    JS中的五种去重方法
    Vue入门教程(2)
  • 原文地址:https://www.cnblogs.com/conprour/p/15528396.html
Copyright © 2011-2022 走看看