Logo __vector__ 的博客

博客

标签
暂无

CF1692F 题解

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2022-06-16 15:10:49

题目翻译

给你一个 $n$ 个元素的数列 $a$。
问是否可以选择 $3$ 个不同的下标 $i,j,k$,使得 $a_i+a_j + a_k$ 的个位是 $3$。

解法

换一种思路,可以枚举所有的数字组合,对于每一种组合判断是否在 $a$ 数组中出现过。
虽然运算次数达到了 $10^{27}$,但是可以进行优化。
可以发现最终答案的个位只和 $a_i,a_j,a_k$ 的个位有关。
也就是说只需要枚举所有的个位组合,然后判断这样的组合在数列 $a$ 的有没有出现就行了。
直接看代码应该更清楚

代码:

#include <bits\/stdc++.h>
using namespace std;
namespace Main
{
	const int maxn=2e5+5;
	int t,n;
	int im[10];\/\/一个桶,im[i] 代表有 im[i] 个元素的个位等于 i
	int a[maxn];
	void main()
	{
		scanf("%d",&t);
		while(t--)
		{
			memset(im,0,sizeof(im));
			scanf("%d",&n);
			for(int i=1;i<=n;i++)
			{
				scanf("%d",&a[i]);
				im[a[i]%10]++;\/\/a[i]的个位出现次数++
			}
			bool flag=0;
			for(int i=0;i<=9;i++)
			{
				if(!im[i])continue;
				for(int j=0;j<=9;j++)
				{
					if(i==j)
					{
						if(im[j]<2)continue;
					}
					else
					{
						if(!im[j])continue;
					}\/\/a 中没出现过,跳过该组合
					for(int k=0;k<=9;k++)
					{
						if(i==j&&j==k)
						{
							if(im[k]<3)continue;
						}
						if(i==k||j==k)
						{
							if(im[k]<2)continue;
						}
						else
						{
							if(!im[k])continue;
						}\/\/a 中没出现过,跳过该组合
						if((i+j+k)%10==3)
						{\/\/该组合是否合法
							printf("Yes\n");
							flag=1;
							break;
						}
					}
					if(flag)break;
				}
				if(flag)break;
			}
			if(!flag)
			{
				printf("No\n");
			}
		}
	}
}
int main()
{
	Main::main();	
	return 0;
}

How to AK ABC256

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2022-06-18 22:18:48

题外话

做出来 ABCD
如果 C 题不犯 sb 错,这场就上 6kyu 了

A

B

C

填数独,爆搜!
复杂度:O(玄学),反正是加剪枝过了

D

差分,$O(n)$
代码:

#include <bits\/stdc++.h>
using namespace std;
namespace Main
{
	typedef long long ll;
	const int maxn=2e5+5;
	int n;
	int L[maxn],R[maxn];
	int cf[maxn];
	void main()
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d%d",&L[i],&R[i]);
			cf[L[i]-1]--;
			cf[R[i]-1]++;
		}
		for(int i=200000;i>=1;i--)
		{
			cf[i]+=cf[i+1];
		}
		int lst=0;
		int r;
		bool flag=0;
		for(int i=1;i<=200000;i++)
		{
			if(cf[i])
			{
				if(!flag)
				{
					lst=i;
					flag=1;
				}
			}
			else
			{
				if(!flag)
				{
					continue;
				}
				else flag=0;
				r=i;
				printf("%d %d\n",lst,r); 
			}
		}
	}
}
int main()
{
	Main::main();
	return 0;
}

E

将 $i$ 连向 $x_i$,边权为 $c_i$
这样就构成了一颗基环树森林。
对于所有树上的点,肯定都能满足要求,先走 $i$ 再走 $x_i$ 就行了。
对于环上的点,例如:
$1 \rightarrow 2 \rightarrow 3 \rightarrow 4 \rightarrow 1$
这样的,肯定要选一个点先走,那么这个点的上一个点就只能委屈了。
也就是要选取环上边权最小的边加入答案

此题结束

#include <bits\/stdc++.h>
using namespace std;
namespace Main
{
	typedef long long ll;
	const int maxn=2e5+5;
	int n;
	int x[maxn],c[maxn];
	int to[maxn];
	bool ins[maxn],vis[maxn];
	ll ans;
	void cir_ans(int u)
	{
		int start=u;
		int imin=0x3f3f3f3f;
		while(1)
		{
			imin=min(imin,c[u]);
			u=to[u];
			if(u==start)break;
		}
		ans+=(ll)imin;
	}
	void dfs(int u)
	{
		if(vis[u])
		{
			if(ins[u])
				cir_ans(u);
			return;
		}
		ins[u]=1;
		vis[u]=1;
		dfs(to[u]);
		ins[u]=0;
	}
	void main()
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&x[i]);
		}
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&c[i]);
		}
		for(int i=1;i<=n;i++)
		{
			to[i]=x[i];
		}
		for(int i=1;i<=n;i++)
		{
			if(!vis[i])
			{
				dfs(i);
			}
		}
		printf("%lld",ans);
	}
}
int main()
{
	Main::main();
	return 0;
}

F

In queue

Kosaraju 算法学习记录

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2022-07-06 13:23:10

根据定义,同一个强连通分量肯定是能互相到达的,也就是说 $u$ 能走到 $v$,那么 $v$ 也能反过来走到 $u$

kosaraju 算法就是先一遍 dfs 记录每一个节点的访问顺序,并建立反边,然后以被访问时间由 晚 $\rightarrow$ 早的顺序遍历每一个尚未标记的节点,设其为 $s_i$,对于每一个 $s_i$,沿着反边往回搜,所以搜到的点也就与它处于同一个强连通分量了,要把这些点标记上

How to AK NOI Online2022-junior

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2022-04-02 11:41:50

前言:

因为 T2忘了写一种情况,导致 $170 \rightarrow 110$,痛失前 25%,pxpxpxpxpxpxpxpxpxpxpxpxpxpxpxpxpxpxpxpx

T1-kingdom

太水了,不写。

T2-math

题目解法:

设 $gcd(x,y) = d$

$x=pd$

$y=qd$

$z=x \cdot y \cdot \gcd(x,y) = pd \cdot qd \cdot d = pqd^3$

因为 $p$ 与 $q$ 互质,$p^2$ 与 $q$ 互质

$d^2 = gcd(p^2d^2,qd^2) = gcd(x^2,\frac{z}{x})$

$ d = \sqrt{gcd(x^2,\frac{z}{x})}$

$y = \frac{\frac{z}{x}}{d} = \frac{\frac{z}{x}}{\sqrt{gcd(x^2,\frac{z}{x})}}$
现在求出了 $y$ 那么代入检验即可

$\color{green}\text{AC 代码:}$

#include <bits\/stdc++.h>
using namespace std;
namespace Main
{
    typedef long long ll;
    int t;
    ll x,z;
    inline ll read()
    {
        ll x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch))
        {
            if(ch=='-')f=-1;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*f;
    }
    inline void write(ll x)
    {
        if(x<0)
        {
            x=-x;
            putchar('-');
        }
        if(x>=10)write(x\/10);
        putchar(x%10^48);
    }
    inline ll gcd(ll a,ll b)
    {
        return !b?a:gcd(b,a%b);
    }
    void main()
    {
        scanf("%d",&t);
        ll y;
        while(t--)
        {
            x=read();
            z=read();
            if(z%x!=0)
            {
                write(-1);
                putchar('\n');
                continue;
            }
            y=(z\/x)\/sqrt(gcd(x*x,z\/x));
            if(x*y*gcd(x,y)!=z)
            {
                write(-1);
                putchar('\n');
                continue;
            }
            write(y);
            putchar('\n');
        }
        #ifndef ONLINE_JUDGE
        system("pause");
        #endif
    }
}
int main()
{
    Main::main();
    return 0;
}

T3-string

咕咕咕

CF1628D1 & CF1628D2题解

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2022-04-10 08:18:55

CF1628D1:

CF1628D1 是这道题的简化版,唯一的不同是数据范围,之后的结论要使用这道题的方法。

想一想这道题的思路,贪心不太可行,因为双方都会选最优方案,双方不可能以贪心的方式来决策,但是如果用 dp 的话可以确保双方都选择了最优方案。

那如何 dp 呢?

  1. 设状态 $f_{i,j}$ 表示第 $i$ 轮游戏时,Bob 要选 $j$ 次加的情况下的 $x$
  2. Bob 的决策:设当前为第 $i$ 轮游戏,Bob 要选 $j$ 次加。如果这一轮 Bob 不选加,那么答案就是 $f_{i-1,j} -t$,如果这一轮 Bob 选加,那么答案就是 $f_{i-1,j-1}+t$,Bob 肯定会选两个答案中最小的,那么 $f_{i,j}=min(f_{i-1,j}-t,f_{i-1,j-1}+t)$
  3. Alice 的决策:因为 $f_{i,j}=min(f_{i-1,j}-t,f_{i-1,j-1}+t)$,所以她需要使 $min(f_{i-1,j}-t,f_{i-1,j-1}+t)$ 尽量大。显然,Alice应当让 $min(f_{i-1,j}-t,f_{i-1,j-1}+t)$ 等于两个数的平均值,显然只有这时候两个数的 min 最大。所以她会让 $t$ 等于 $f_{i-1,j}$ 和 $f_{i-1,j-1}$ 之差的平均值,这样 $min(f_{i-1,j}-t,f_{i-1,j-1}+t) = \frac{f_{i-1,j}-t,f_{i-1,j-1}+t}{2}$ 。
    4.最终的转移方程:$f_{i,j} = \frac{f_{i-1,j}-t,f_{i-1,j-1}+t}{2}$,另外,边界条件:$f_{i,0} = 0,f_{i,i} = i \cdot k$
    当 $n=m$ 时,答案为 $k \cdot n$
    注意:
    因为要取模,所以除以 2 时,应当乘上 2 在模 1e9+7 意义下的逆元,这个逆元用 exgcd 可以轻松求出。这里把我用 exgcd 求出的逆元贴出来:500000004

CF1628D1 的 AC 代码:

#include <bits\/stdc++.h>
using namespace std;
namespace Main
{
    typedef long long ll;
    const ll mod=1e9+7;
    int t;
    const int maxn = 2005;
    ll inv;
    ll f[maxn][maxn];
    int n,m,k;
    inline int read()
    {
        int x = 0, f = 1;
        char ch = getchar();
        while (!isdigit(ch))
        {
            if (ch == '-')
                f = -1;
            ch = getchar();
        }
        while (isdigit(ch))
        {
            x = (x << 1) + (x << 3) + (ch ^ 48);
            ch = getchar();
        }
        return x * f;
    }
    void write(int x)
    {
        if(x<0)
        {
            x=-x;
            putchar('-');
        }
        if(x>=10)write(x\/10);
        putchar(x%10^48);
    }
    int x,y;
    void exgcd(int a,int b)
    {
        if(b==0)
        {
            x=1;
            y=0;
            return;
        }
        exgcd(b,a%b);
        int tmp=x;
        x=y;
        y=tmp-a\/b*y;
    }
    inline void solve()
    {
        n=read();
        m=read();
        k=read();
        for(int i=1;i<=n;i++)
        {
            f[i][0]=0;
            f[i][i]=(ll)i*(ll)k;
            f[i][i]=f[i][i]%mod;
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<i;j++)
            {
                f[i][j]=(f[i-1][j-1]+f[i-1][j])%mod*inv%mod;
            }
        }
        write((int)f[n][m]);
        putchar('\n');
    }
    void main()
    {
        exgcd(2,mod);
        inv=(x%mod+mod)%mod;
        t=read();
        while(t--)
        {
            solve();
        }
        #ifndef ONLINE_JUDGE
        system("pause");
        #endif
    }
}
int main()
{
    Main::main();
    return 0;
}

CF1628D2:

这道题与上一道题唯一的区别是数据范围扩大了,不能再 $O(nm)$ dp 了。
可以发现最终的答案都是从直接或间接从 $f_{i,i}$ 转移过去的,所以是不是可以只考虑 $f_{i,i}$ 对答案的贡献?
$f_{i,i}$ 的贡献可以想到,就是由 $(i,i)$ 走到 $(n,m)$ 的路径数( 从任意一点 $(i,j)$ 只能走到 $(i+1,j)$ 或 $(i+1,j+1)$),再乘上每条路径产生的贡献。
由 $(i,i)$ 走到 $(n,m)$ 的路径数就是从 $n-i-1$ 条向上走的路径中选择 $m-i$ 条路径既向上走又向右走,也就是 $C_{n-i-1}^{m-i}$。$(i,i)$ 的初始值为 $i \cdot k$,路径中每走一个点,就会将其贡献除以 2,一共会除以 $n-i$ 次 2,也就是除以 $2^{n-i}$。
所以,答案就是 $\sum_{i=1}^m \frac{C_{n-i-1}^{m-i} \cdot i \cdot k}{2^{n-i}}$
快速幂和组合数肯定都会写,不说了。

CF1628D2 的 AC 代码:

#include <bits\/stdc++.h>
using namespace std;
namespace Main
{
    typedef long long ll;
    const ll mod=1e9+7;
    int t;
    const int maxn = 1e6+5;
    ll n,m,k;
    inline ll ksm(ll a,ll b,ll p)
    {
        ll ret=1;
        while(b)
        {
            if(b&1)ret=ret*a%p;
            a=a*a%p;
            b>>=1;
        }
        return ret;
    }
    inline ll ny(ll a,ll p)
    {
        return ksm(a,p-2,p);
    }
    
    ll fact[maxn];
    inline ll C(ll n,ll m)
    {
        if(n<m)return 0;
        return fact[n]*ny(fact[m],mod)%mod*ny(fact[n-m],mod)%mod;
    }
    inline void solve()
    {
        scanf("%lld%lld%lld",&n,&m,&k);
        ll ans=0;
        if(n==m)
        {
            printf("%lld\n",k*n%mod);
            return;
        }
        for(ll i=1;i<=m;i++)
        {
            ans+=k*i%mod*C(n-i-1,m-i)%mod*ny(ksm(2,n-i,mod),mod)%mod;
            ans%=mod;
        }
        printf("%lld\n",ans);
    }
    void main()
    {
        fact[0]=1;
        for(int i=1;i<=1000000;i++)
        {
            fact[i]=fact[i-1]*(ll)i;
            fact[i]%=mod;
        }
        scanf("%d",&t);
        while(t--)
        {
            solve();
        }
        #ifndef ONLINE_JUDGE
        system("pause");
        #endif
    }
}
int main()
{
    Main::main();
    return 0;
}

How to AK ABC247

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2022-04-15 23:31:13

前言:

整了一周的 whk ,总算能写写代码了。

A - Move Right

签到题

B-Unique Nicknames

这道题虽然也是一个 $O(n^2)$ 的暴力能过的签到题,但我非要调 $O(n log n)$ 的方法,结果吃了 19 个罚时...........(不过还好是虚拟赛)

C-1 2 1 3 1 2 1

这道题直接按照题目模拟即可,签到题 (然而我犯智障吃了一个罚时)

D-Cylinder

这道题还是签到题。
可以定义一个结构体,用来存储连续的一段写有相同数字的球,如下:

struct Node
{
   int sum,val;
}node[maxn];

sum 代表当前段的球数,val 代表当前段的球上面的数字。
node 作为一个栈,加入新的球时,如果新加入的那些球与栈顶的数字相同,那么将它们合并,否则将新加入的球作为一个新的栈顶元素加入栈中。
删除球的时候也差不多,就不说了。

E-Max Min

暴力肯定都会,来说一说如何对暴力进行优化,使其复杂度降为 $O(n)$(就是官方题解的做法)。

  1. 数组中有一部分元素大于 $x$,或小于 $y$,这些元素的存在实际上把数组分成了几个有效的区间。因为任何区间都不可能包含这些元素,所以可以先利用这些元素把数组划分成几个独立的区间。显然,这些区间可以单独计算答案,不会互相干扰,不会互相干扰的原因是如果要干扰肯定需要经过那些 (大于 $x$,或小于 $y$) 的元素,但这是不可能的。
  2. 划分完区间之后,就可以对每个区间从左到右枚举 $l$,每次加上 $r$ 的取值范围大小即可。

代码:

#include <bits\/stdc++.h>
using namespace std;
#define int long long
namespace Main
{
    typedef long long ll;
    const int maxn=2e5+5;
    int a[maxn];
    int sta[maxn];
    int top=0;
    int n,x,y;
    ll get_ans()
    {
        int j=1;
        int cnt_x,cnt_y;
        cnt_x=cnt_y=0;
        ll ans=0;
        for(int i=1;i<=top;i++)
        {
            for(;j<=top&&(cnt_x==0||cnt_y==0);j++)
            {
                if(sta[j]==x)cnt_x++;
                if(sta[j]==y)cnt_y++;
            }
            if(cnt_x&&cnt_y)
            {
            	\/\/此时j-1为r的最小取值
                ans+=(ll)(top-j+2);
            }
            if(sta[i]==x)cnt_x--;
            if(sta[i]==y)cnt_y--;\/\/l向右移动,清除当前
        }
        return ans;
    }
    void main()
    {
       scanf("%d%d%d",&n,&x,&y);
       for(int i=1;i<=n;i++)
       {
           scanf("%d",&a[i]);
       }
       ll out=0;
       int i=1;
        while(i<=n)
        {
            top=0;
            for(;i<=n&&(a[i]<=x)&&(a[i]>=y);i++)
            {
                sta[++top]=a[i];
            }
            if(top)
            {
                out+=get_ans();
            }
            else
            {i++;}
        }
        cout<<out;
    }
}
signed main()
{
    Main::main();
    #ifndef ONLINE_JUDGE
    system("pause");
    #endif
    return 0;
}

F - Cards

我是照着 $\color{black}\text{c}\color{red}\text{zyjr}$ 大佬的代码才看懂题解的。(atcoder id=cz_yjr)

考虑把每对 $(p_i,q_i)$ 相连,这样就形成了一些连通块,例如 $(a \rightarrow b) \rightarrow (b \rightarrow c) \rightarrow (c \rightarrow d)$ 这样的,设第 $i$ 个连通块大小为 $size_i$,那么每个连通块都要选择一些不同的数字,使得所有最后所有连通块选择的数字正好有 $n$ 个不同的。
可以提前预处理出连通块大小为 $i (i \in [1,n])$ 时的方案数,记为 $f_i$。

  1. $f_1 = 1,f_2=3$
  2. $f_i = f_{i-1}+f_{i-2} (i \ge 3)$
    最后答案就是所有连通块方案数相乘

P8289题解

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2022-04-17 21:02:09

前言:

这道题是省选的签到题,然而我交了很多遍才 AC

题目注意事项:

  1. #define <name> <content> 中的 content 可以为空

  2. 连续在一起的大小写字母和数字以及下划线应该视作同一个标识符

题目做法:

读入:

这里的读入有亿些坑,在此说一下 读入 $n$ 之后,应该使用 getchar 来吸收换行符,不然会挂。
读入每一行的字符串时,可以这样读入:

fgets(line, maxn, stdin);
\/\/line是临时存储每一行字符串的char数组
\/\/maxn是数组大小

至于如何读入宏,首先可以使用 sscanfline 数组将开头的 #define#undef,以及宏名读入,具体如下:

sscanf(line,"%s%s",define.tmp,define.name);
\/\/define.tmp 是 "#define" 或 "#undef"
\/\/define.name 是宏名

最后的宏的内容,也就是 content,应该从预处理指令的前两个单词的末尾的向后两个位置开始依次一个一个的读入每个字符。具体如下:

for(int i=ttmp,cnt=0;i<size_line;i++,cnt++)
{
	if(line[i]=='\n')break;
	define.val[cnt]=line[i];
   	\/\/define.val 是宏的内容(content)
   	\/\/ttmp 是预处理命令的前两个单词的末尾的向后两个位置
   	\/\/也就是预处理命令第三个单词开始的位置
   	\/\/size_line 是 line数组的大小
}

之所以不能直接读入是因为宏的内容 content 可以为空

宏的存储

因为 map 的复杂度是 $O(logn)$,容易被卡,最好用 unordered_map,这样复杂度是 $O(1)$ 的,因为 map 用的是红黑树,unordered_map 用的是哈希表。
定义一个 unordered_map 来存储每个宏名替换之后的内容:

unordered_map<string,string> def;

然后 def[name]=content 就行了

宏的展开

注:line 数组是临时存储每一行字符串的。此时 string ans 用来存储答案。
遍历 line 数组,按照题目要求找标识符。找到一个标识符,首先判断它是不是一个有效的宏名,如果不是,那么 ans 直接加上这个标识符即可,如果它是一个有效的宏名,那么对其进行展开之后 ans 再加上它,下面来说一下如何进行展开。

因为一个宏展开之后可能还需要继续展开,这样就很麻烦,使用 dfs 可以方便的进行递归展开。来说一下怎么 dfs:

定义:string dfs(string hong)

其中 dfs 的返回值是宏展开之后的字符串,hong 是待展开的宏名。

递归到某个宏,首先把这个宏变成这个宏第一次展开之后的字符串,也就是 hong = def[hong],并定义一个临时数组 string str 来存储当前宏完全展开之后的最终字符串,遍历 hong 数组,查找每一个标识符,如果这个标识符 name 是一个有效的宏名,那么对其 dfs 递归展开:str+=dfs(name),否则直接加入 str 数组。
最后返回 str 数组。

那么如何处理无线递归展开呢?
可以定义一个 unordered_map<string,bool> vis 来记录当前递归正在展开的宏名,每递归到一个宏名 name,就将这个宏名记录下来:vis[name]=1,如果发现当前宏名与某个正在展开的宏名相同,也就是 if(vis[name]==1),那么当前宏名不作展开,直接把宏名返回即可。

AC 代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <unordered_map>
#include <vector>
using namespace std;
namespace Main
{
	const int maxn=105;
	int n;
	char line[maxn];
	unordered_map<string,string> def;
	int size_line;
	struct Define
	{\/\/用来临时存储正在读入宏的信息
		char tmp[10];
		char name[maxn];
		char val[maxn];
	}define;
	string ans_line;\/\/存储每个蒲通文本宏展开后的样子
	string temp;
	unordered_map<string,bool> vis;
	bool isletter(char s)
	{
		if(isdigit(s))return 1;
		if(s=='_')return 1;\/\/注意数字和下划线与字母一起组成标识符
		if(s-'a'>=0&&s-'a'<26)return 1;
		if(s-'A'>=0&&s-'A'<26)return 1;
		return 0;
	}
	string dfs(string hong)
	{
		string ttttmp=hong;\/\/临时存储原来的宏名
		hong=def[hong];\/\/把hong 变成其一次展开后的样子
		if(vis[ttttmp])return ttttmp;
		\/\/如果与正在进行展开的某个宏名相同,返回
		vis[ttttmp]=1;
		string str="";
		string temp="";\/\/存标识符
		for(int i=0;i<hong.size();i++)
		{
			if(hong[i]=='\n')break;
			\/\/	cout<<"temp: "<<temp<<endl;
			if(isletter(hong[i]))
			{
				temp+=hong[i];
			}
			else
			{
				if(def.count(temp))
				{\/\/连续字母结束,处理一下宏
					\/\/不要忘记读入完整个字符串之后还要展开一下temp
					str+=dfs(temp);
				}
				else
				{
					str+=temp;
				}
				temp=hong[i];
				if(def.count(temp))
				{\/\/如果当前文本是一个宏,替换一下
					str+=dfs(temp);
				}
				else
				{\/\/不是宏,不做处理
					str+=temp;
				}
				temp="";
			}
		}
		if(def.count(temp))
		{
			str+=dfs(temp);
		}
		else
		{
			str+=temp;
		}
		vis[ttttmp]=0;
		return str;
	}
	void main()
	{
		cin>>n;
		getchar();
		while(n--)
		{
			fgets(line, maxn, stdin);
			size_line=strlen(line);
			if(line[0]=='#')
			{\/\/预处理指令
				sscanf(line,"%s%s",define.tmp,define.name);
				int ttmp=strlen(define.tmp)+strlen(define.name)+2;
				memset(define.val,0,sizeof(define.val));
				for(int i=ttmp,cnt=0;i<size_line;i++,cnt++)
				{
					if(line[i]=='\n')break;
					define.val[cnt]=line[i];
				}
				if(define.tmp[1]=='d')
				{
					def[define.name]=define.val;
				}
				if(define.tmp[1]=='u')
					def.erase(define.name);\/\/#undef
				putchar('\n');
				continue;
			}
			else
			{\/\/蒲通文本
				ans_line="";
				temp="";
				for(int i=0;i<size_line;i++)
				{
					if(line[i]=='\n')break;
					\/\/	cout<<"temp: "<<temp<<endl;
					if(isletter(line[i]))
					{
						temp+=line[i];
					}
					else
					{
						if(def.count(temp))
						{\/\/连续字母结束,处理一下宏
							\/\/不要忘记读入完整个字符串之后还要展开一下temp
							ans_line+=dfs(temp);
						}
						else
						{
							ans_line+=temp;
						}
						temp=line[i];
						if(def.count(temp))
						{\/\/如果当前文本是一个宏,替换一下
							ans_line+=dfs(temp);
						}
						else
						{\/\/不是宏,不做处理
							ans_line+=temp;
						}
						temp="";
					}
				}
				if(def.count(temp))
				{
					ans_line+=dfs(temp);
				}
				else
				{
					ans_line+=temp;
				}
				cout<<ans_line<<endl;
			}
		}
	}

}
int main()
{
	Main::main();
	return 0;
}

P8236 魔法的力量 题解

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2022-05-06 22:18:40

题目解法:

考虑一下每个石子被选中的概率。可以看出,到第 $i$ 轮合并之前,还剩下 $n-i+1$ 堆石子,那么显然,第 $i$ 轮合并每一堆石子 $j$ 有 $\frac{2}{n-i+1}$ 的概率被选上。
那么显然,答案就是 $(\sum_{i=1}^{n} a_i) \cdot (\sum_{i=2}^{n} \frac{2}{i})$

代码:

#include <bits\/stdc++.h>
using namespace std;
namespace Main
{
	typedef long double ld;
	int n;
	const int maxn=505;
	ld a[maxn];
	void main()
	{
		scanf("%d",&n);
		ld ans1=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%Lf",&a[i]);
			ans1+=a[i];
		}
		ld ans2=0;
		for(int i=2;i<=n;i++)
		{
			ans2+=ld(2.0)\/ld(i);
		}
		printf("%.50Lf",ans2*ans1);
	}
}
int main()
{
	Main::main();
	return 0;
}

期中考试游寄-2022-初一下学期

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2022-05-13 18:40:44

Day -2

什么!要期中考试?!!!我都卷了半个月 OI 了,开始复习

Day -1

晚上打了场 Atcoder,顺利切掉 ABCD,涨了大分 $\color{brown}\text{517} \rightarrow \color{brown}\text{623}$,把期中考试 rp 耗光了

Day 0

复习了一堆历史,语文相关的东西

Day 1

先考的语文,早上大约有 30 分钟复习时间,就背了背文常(我以为书最后几页的东西应该不会考,结果考了)。
开始考试,一看 T1,还好,就快速做出前五个小题。第六个小题死活想不出来(就是那个我以为不会考的),还好只有 $1$ 分。看后面的题,woc,要解释很多没学过的单字,就根据上下文写了几个应该是对的的。此时过去了 10 分钟。下一题是一个文言文阅读,看了一下题目难度还好,就比较轻松的做了出来。一看时间,已经过了 40 分钟,但是还有两道阅读题大题没做,心里一阵慌。快速的把题做过去一遍,一堆没把握的,但是也没时间管了,开始整作文,此时过去了 60 分钟。一看作文题目,什么!要写心愿?!要求 600 字!想了一会,没想出来。一边想一边赞美着出题人,忽然想到了一个合适的人物可以写,就什么都不管狂写。大概花了 45 分钟写完,大约 700 字。还剩下 15 分钟,仅仅是检查了一下答案没有抄错就交了上去。

课间 30 分钟就休息了一会,背了一会题
然后考政治。
先开选择题,WA!全是送分题,快速搞定,看大题。T1 只有 6 分,但是我还是写了一大堆才敢放下。一看 T2,貌似也是送分的,但是,要答的东西太多了,打完之后已经过了 25 分钟,心里一阵惊慌。看下面的题,c!书上没有一道题和这道题有关系,赞美完了一遍出题人之后,瞎答了两条就过。现在还剩 4 道大题,但是只剩 15 分钟,我只能靠着 $n^2$ 过 $10^{18}$ 的手速了,然后就是一顿........最后打铃的那一刻答完了卷。考完对了一下,不少人答不完卷,我“感谢”出题人。

下午的历史,没啥好说的。

另外和某个同学吹下了牛逼,数学不超过他 30 分,我就

Day 2

先考数学,由于我之前数学次次 AK,我对我的要求是 120。(主要是想当数学课代表)
先把选择题前 11 题做完,T12 貌似不太会,就先空着。做了一下填空题,woc,怎么又有不会的,心态崩溃了,结果接下来我本来会的题都不会了,我只得全部空过去,把我会的题全切掉,总算调整好了心态。此时还剩 30 分钟,然后返回去切没做出来的题,成功切掉。最后 5 分钟检查出了一道错题,考试结束。

生物没啥好说的

Day 3


开始卷 OI

Day 10

出成绩了,数学有一道题犯贱(正负号写反)导致只得了 110pts。总成绩:语蚊91 + 数学110 + 英语112.6 + 历史92 + 地理95 + 生物93 + zz84 = 677.6pts。
和前一名只差0.8分 [大哭]

SDOI2022 线上比赛游记

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2022-05-13 19:11:12

我提前 4 年打 $\color{purple}\text{省选}$ 完全就是来找虐的(我现在初一六年级)。

Day 0 - 上午

先开 T1,一看题面说是 $q$ 组询问,每一组询问都要维护一个数组 $c$,数组大小为 $n$,每个元素都为 $0$,$1$ 或 $-1$。让求一个区间,使得 $\sum^{r}{l} b_i \cdot c_i$ 最大。$n,q \le 10^6$。
一看上去,这 $c$ 数组还得根据题目每次自己生成,这还不得直接爆炸。想了一会,觉得这道题 $O(logn)$ 平衡树查询某个数比较合适,但是过了一会 Hack 掉了自己的思路。然后就想想暴力分,我尝试使用 st 表实现 $O(n^2logn)$,但是想了一会发现假了。只得开 T2。
T2 让求的是 $\sum^{n}
{1}x^i \cdot y^{a(i)} \cdot z^{b(i)}$,$a(i)$ 是十进制 $i$ 转换为二进制之后包含的 $1$ 的数量,$b(i)$ 是十进制 $i$ 转换为三进制后每一位的和。$1 \le n \le 10^{13}$。一看这数据范围,感觉应该是 $O(\sqrt n \cdot logn)$,但是想了一会想不出来。就盯上了 $1 \le n \le 10^7$ 的暴力分。我快速打出了一个 $O(nlogn)$ 的暴力,过了第一个样例。我又手造了一组极限数据,结果.......跑了 27s,不会省选就要这样爆零了把。
我就开始卡常,我把 long long 能换的全换成 int,一测,变成了 14s,快了一倍!我再思考别的卡常思路。我想起来我曾经通过循环展开用大暴力 AC 过一道紫题,我觉得可以试试把循环展开应用一下。然后........接下来 20 分钟都是在进行展开。展开完之后一测,Yeah!又卡掉了一半的常数,$14s \rightarrow 7.5s$。接下来我又把计算 $a(i)$ 的函数从我自己写的换成 c++ 的内置函数,然后 $7.5s \rightarrow 7.1s$。这时候,我发现不能再优化了,开了 O2 也要跑 6.8s。没办法,我的算法彻底假了,只能去想 $O(n)$ 算法。结果我发现我被降智了,只需要一遍预处理就能砍掉快速幂.............然后我把没优化之前的代码改了改,就过了暴力部分的极限数据(我花了一个小时来做的优化全白费了),差不多结束了。

估分: 0+15+0+0=15pts

Day 0 - 下午

看了看 T1,说是对于每个 $i \in [1,n \cdot k]$,计算有多少个可能的树的最大独立权集等于 $i$,(树的节点数为 $n$,每个点的点权为 $[1,k]$ 中的任意一个数)。只能想到 $O(n! \cdot k^n)$ 的暴力,能光荣的获得 $\color{red}\text{0}$ 分。
那就先跳下一题,一看,这道题树链剖分板子,但是空间卡的很死,时限倒是很长。然后就盯着它的特殊性质研究了一个小时,发现做不出来,开 T3,woc 一道巨难的数学题,连题都读不懂,感觉这道题至少 $\color{black}\text{NOI}$ 难度,只得跳回 T1。这时候发现它的 $n \le 8,k \le 5$ 的部分可以使用树形 dp 来做(实际上这一部分就是 P1352没有上司的舞会)。设 $f_{i,1}$ 代表当前点选的最优价值,$f_{i,0}$ 代表当前点不选的最优价值。$O(k^n)$ 枚举每个可能的树,对于每个树 $O(n)$ 计算。这样就有了 25pts。写出来之后感觉再做下去没啥用,就提交代码离场了。
估分:25+0+0=25pts

最后

总分估计:15+25=40pts
我还是太菜了

UPD:

官方成绩出来了:15+25=40pts,和估分一样。另外看了一下 B 队最后一名的省选成绩是 199pts,还是差的很远很远

共 320 篇博客