Coduck S14754 赵廷赫
一,比赛情况
一,四题0分,二题30分,三题20分,总分50分。
二,赛中概况
先做了第一题,会,算法也对,但是运行出了问题,改了45分钟,还是不对。然后去做第二题,算法只在部分情况下正确。第三题方法会也不会,用暴力得了了二十分,第四题,完全不会+骗分失败,0分。
三,补题报告
T1:
题目:
重复判断
时间限制:1秒 内存限制:256M
题目描述
小可需要判断一个字符串a,是否由另一个字符串b生成出来的,所谓的生成,其实就是把字符串b重复若干次,即:判断字符串a是否是字符串b重复若干次得到的。
输入描述
第一行:输入一个数字 t,表示共有 t 组询问。
接下来 t 行每行两个字符串 a 和 b。
输出描述
输出 t 行,每行输出 YES
或NO
。
输入样例
2
addaddadd add
abcd bcda
输出样例
YES
NO
数据描述
10%的数据下:字符串长度均<11。
题目分析:
判断一个字符串a是否可以由一个或多个字符串b连接到一起得到。
可以使用模拟法,模拟b生成a的过程。
AC代码:
#include<bits/stdc++.h>
using namespace std;
string a,b,s;
bool cmp(string a,string s)
{
int al=a.size(),sl=s.size();
if(al!=sl)
{
return 0;
}
for(int i=0;i<sl;i++)
{
if(s[i]!=a[i])
{
return 0;
}
}
return 1;
}
int main()
{
int t,al,bl,sl;
cin>>t;
bool bo,f[t+10];
for(int i=1;i<=t;i++)
{
cin>>a>>b;
bl=0;
s="";
al=a.size();
bl=b.size();
sl=0;
if(al<bl)
{
f[i]=0;
break;
}
if(al==bl)
{
if(a==b)
{
f[i]=1;
break;
}
else
{
f[i]=0;
break;
}
}
while(sl<=al)
{
s+=b;
sl+=bl;
if(cmp(a,s))
{
f[i]=1;
bo=1;
break;
}
}
if(bo==0)
{
f[i]=0;
}
}
for(int i=1;i<t;i++)
{
if(f[i])
{
cout<<"YES"<<endl;
}
else
{
cout<<"NO"<<endl;
}
}
if(a[t])
{
cout<<"YES";
}
else
{
cout<<"NO";
}
return 0;
}
T2:
歪果仁学乘法
时间限制:1秒 内存限制:128M
题目:
题目描述
歪果仁不太会乘法,原因是他们被不过九九乘法表,小可听到之后,提出了一种不需要九九乘法表也可以计算乘法的方式,对于a × b:
1.将a,b的每一位上的数码画成线,不同位之间分隔开。
2.a 和 b 的方向垂直画出。
3.数出每个方向上交点的个数,即是 c 对应位置上的数码。
样例图给出了计算12 ×13的方法:
1.红色线分别画出 1 条和 2 条;
2.蓝色线分别画出 1 条和 3 条;
3.数出红、蓝色线的交点个数,依次为 1,5,6 个;
4.得到答案:12 × 13 = 156。
给出两个数字 a, b,求它们的乘积时交点的总个数是多少。
输入描述
输入两个正整数 a和 b 。
输出描述
输出交点的总个数。
输入样例
12 13
输出样例
12
样例图如下:
一共12个交点。
数据描述
对于100%的数据:1<=a,b<=99。
测试点1~3:1<=a,b<=9。
测试点4~6:计算 a × b 时,不会进位。
测试点7~10:无特殊限制。
题目解析:
解题思路:将a,b的各位分别相乘,答案等于和。
AC代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a,b,ag,bg,as,bs,ans;
cin>>a>>b;
if(a<10&&b<10)
{
cout<<a*b;
return 0;
}
ag=a%10;
as=a/10;
bg=b%10;
bs=b/10;
ans=bs*as+bs*ag+bg*as+bg*ag;
cout<<ans;
return 0;
}
时间复杂度为O(1)。
T3:
题目:
去重求和
时间限制:3秒 内存限制:256M
题目描述
小可有一个长度为 n 的序列 a_iai。
他定义sum(l,r)sum(l,r),为a[l]a[l] ~ a[r]a[r] ,这些数去重之后的和。
请求出
输入描述
第一行:输入一个正整数 n ,表示序列长度。
第二行:输入n个整数,表示序列 a 。
输出描述
输出答案,答案对10^9+7109+7取模。
输入样例
4
1 1 4 5
输出样例
51
sum(1,1)=1,sum(1,2)=1,sum(1,3)=5,sum(1,4)=10sum(1,1)=1,sum(1,2)=1,sum(1,3)=5,sum(1,4)=10
sum(2,2)=1,sum(2,3)=5,sum(2,4)=10sum(2,2)=1,sum(2,3)=5,sum(2,4)=10
sum(3,3)=4,sum(3,4)=9sum(3,3)=4,sum(3,4)=9
sum(4,4)=5sum(4,4)=5
因此答案为 1 + 1 + 5 + 10 + 1 + 5 + 10 + 4 + 9 + 5 = 51。
数据描述
对于100%的数据:1<=n<=5*10^5,1<=a[i]<=10^9
题目解析:
解题思路:
(1)找特殊情况:
所有数据都不相同,总结规律。
(2)推广到一般情况:
将区间统计变成贡献统计,利用求贡献的算法解决问题。
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
typedef long long ll;
const int mod = 1e9 + 7;
int n, a[N];
map<int,int>mp;
int l[N], r[N];
int main()
{
cin >> n;
for(int i = 1; i <= n; ++i)
{
cin >> a[i];
mp[a[i]] = 1;
}
mp.clear();
for(int i = 1; i <= n; ++i)
{
l[i] = mp[a[i]] + 1;
mp[a[i]] = i;
}
ll ans = 0;
for(int i = 1; i <= n; ++i)
{
ans += 1ll * a[i] * (i - l[i] + 1) % mod * (n - i + 1) % mod;
ans %= mod;
}
cout << ans << endl;
return 0;
}
T4:
题目:
点集操作
时间限制:3秒 内存限制:256M
题目描述
小可在学习图论,他有一个有向无环图,他想知道对这个图做任意次modify(i,j)modify(i,j)操作之后的图中剩余的最小点数,其中1\leq i,j\leq n1≤i,j≤n,其中modify(i,j)modify(i,j)为一次操作:
1.任选不同的两个点i,ji,j
2.称 A_iAi 为 ii 能到达的所有点组成的点集, A_jAj 为 jj 能到达的所有点组成的点集 。(注意:每个点可以到达的点集包含这个点本身)
3.设 B 为一个最大的点集,满足 B 既是 A_iAi 的子集,又是A_jAj的子集 。
4.将 B 在图中变成一个新点,B 内的所有边全部删除。点集 B 以外的点与点集 B 以内的点的连边关系转移到新点上。
输入描述
第一行两个数 n,m。
接下来 m 行每行两个数表示一条有向边 。
输出描述
一行一个数表示最小剩余点数。
输入样例
5 6
2 1
5 1
2 3
4 3
5 4
4 1
输出样例
3
题目解析:
样例画图可得,把有入度的相关点的重叠点,变成一个大点B,是一次modify操作。
在一个单向链上,只需要让链头的两个点进行一次操作就可以将整个链变成两个点。
所以每次操作可以在一条所含点数超过 2 的单向链上进行,直至不能继续操作,剩下的点的个数即为图中剩余的最小点数。
由上面操作的特殊性可以知道所有入度为 0 的点删不掉,所有满足所有入边对应点入度为 0 的点也删不掉,可以将这些点(所有满足所有入边对应点入度为 0 的点)看成新点。统计这些点个数即可。
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e6+5;
int n,m,x[MAXN<<1],y[MAXN<<1],in[MAXN];
int head[MAXN],num,ans;
bool b[MAXN],vis[MAXN];
vector<int>v;
queue<int>q;
struct node
{
int to,next;
}e[MAXN<<1];
void add(int u,int v)
{
e[++num].to=v;
e[num].next=head[u];
head[u]=num;
}
int main()
{
cin >> n >> m;
for(int i=1;i<=m;++i)
{
cin >> x[i] >> y[i];
add(x[i],y[i]);
in[y[i]]++;
}
for(int i=1;i<=n;++i)
{
if(!in[i])
{
v.push_back(i);
ans++;
}
}
for(int i=1;i<=m;++i)
{
if(in[x[i]])b[y[i]]=1;
}
for(int i=0;i<v.size();++i)
{
for(int j=head[v[i]];j;j=e[j].next)
{
if(!b[e[j].to])
{
b[e[j].to]=1;
ans++;
}
}
}
cout << ans;
return 0;
}
四,比赛总结
比赛1题难度不太高,2题算法很容易忽略进位3题算法难度还可以,但是思维难度高,很难想到正确算法,4题骗分都很难,更别提AC了。
这套题不难,主要是1题运行出了问题,2题算法不完全正确。