这套题目100+10+0,rank21,贼菜,T1推了2hour,T2把数组类型int打成了char,10分(大暴力90,去重后100),T370分规律,后面30防AK,6k代码量……
T1
问题 A: 数列1
时间限制: 1 Sec 内存限制: 128 MB
题目描述
输入
输出
样例输入
0 1
2000000000 1
样例输出
no
yes
提示
Solution
具体看代码
CODE
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll I=1000000000;
ll a,b;
int main()
{
while (scanf("%lld%lld",&a,&b)==2)
{
if (a==I)
{
if (b==0) printf("no\n");
else printf("yes\n");
}
else
{
if (abs(a)<=I || a+b==I) printf("no\n");
else printf("yes\n");
}
}
return 0;
}
T2
问题 B: 单词
时间限制: 5 Sec 内存限制: 512 MB
题目描述
输入
输出
样例输入
4 3
xyz
xyz
zzx
xzz
样例输出
2
1
2
1
提示
Solution
做法非常多
- O(n^2m)大暴力,没有任何优化,90分
- tire树,再加入前dfs整棵树,相对于大暴力少了一些重复走的边,卡过总用时25s
- 排序+去重+大暴力 总用时 10s
- 分类,n较小时O(n^2m)大暴力,m较小时O(3^m*3^m*m),枚举集合与集合中的数,各3^m,在m位比较,非常暴力。
- 对4的优化,前一半用3的方法排序+去重,后一半DP
CODE
trie树
//time:25s;
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN=100005;
int tire[MAXN][3],val[MAXN];
ll ans[MAXN];
char str[MAXN];
int n,m,cnt=0;
void insert(char *s)
{
int len=strlen(s),now=0;
for (int i=0;i<len;i++)
{
int j=s[i]-'x';
if (tire[now][j]) now=tire[now][j];
else now=tire[now][j]=++cnt;
}
val[now]++;
}
void dfs(int now,int len,int num)
{
if (len==m)
{
ans[num]+=(ll)val[now];
return;
}
for (int i=0;i<3;i++)
if (tire[now][i]) dfs(tire[now][i],len+1,num+(str[len]-'x'==i));
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%s",str);
dfs(0,0,0);
insert(str);
}
for (int i=0;i<=m;i++)
printf("%lld\n",ans[i]);
return 0;
}
排序+去重
//time:10s;
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN=100005;
string str[MAXN],s[MAXN];
ll sum[MAXN];
int n,m,n2,num[MAXN];
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) cin>>str[i];
sort(str+1,str+1+n);
for (int i=1;i<=n;i++)
if (str[i]!=str[i-1])
s[++n2]=str[i],num[n2]=1;
else num[n2]++;
for (int i=1;i<=n2;i++) sum[m]+=(ll)(num[i]-1)*num[i]/2;
for (int i=1;i<=n2;i++)
for (int j=i+1;j<=n2;j++)
{
int x=0;
for (int k=0;k<m;k++)
if (s[i][k]==s[j][k]) x++;
sum[x]+=(ll)num[i]*num[j];
}
for (int i=0;i<=m;i++)
printf("%lld\n",sum[i]);
return 0;
}
正解
表示没懂DP
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN=100005;
string str[MAXN],s[MAXN];
ll sum[MAXN],mi3[MAXN],dp[MAXN][12],dp1[MAXN][12];
int n,m,n2,num[MAXN],ss[MAXN];
void solve_small_n()
{
for (int i=1;i<=n;i++) cin>>str[i];
sort(str+1,str+1+n);
for (int i=1;i<=n;i++)
if (str[i]!=str[i-1])
s[++n2]=str[i],num[n2]=1;
else num[n2]++;
for (int i=1;i<=n2;i++) sum[m]+=(ll)(num[i]-1)*num[i]/2;
for (int i=1;i<=n2;i++)
for (int j=i+1;j<=n2;j++)
{
int x=0;
for (int k=0;k<m;k++)
if (s[i][k]==s[j][k]) x++;
sum[x]+=(ll)num[i]*num[j];
}
for (int i=0;i<=m;i++)
printf("%lld\n",sum[i]);
}
void solve_small_m()
{
for (int i = 1; i <= n; i++) {
int now = 0;
for (int j = 1; j <= m; j++) {
now *= 3;
char k;
for (k = getchar(); k <= 32; k = getchar());
now += k - 'x';
}
ss[now]++;
}
mi3[0] = 1;
for (int i = 1; i <= m; i++) mi3[i] = mi3[i - 1] * 3;
for (int i = 0; i < mi3[m]; i++) dp1[i][m] = ss[i];
for (int i = 0; i < m; i++) {
memcpy(dp, dp1, sizeof dp);
for (int j = 0; j < mi3[m]; j++) {
int s1 = j / mi3[i] % 3, s2 = j - s1 * mi3[i];
for (int t = 0; t < 3 * mi3[i]; t += mi3[i])
if (t != s1 * mi3[i])
for (int p = m - i; p <= m; p++) dp[s2 + t][p - 1] += dp1[j][p];
}
memcpy(dp1, dp, sizeof dp);
}
for (int i = 0; i < mi3[m]; i++)
for (int p = 0; p <= m; p++)
sum[p] += 1LL * ss[i] * dp1[i][p];
sum[m] = sum[m] - n;
for (int i = 0; i <= m; i++) sum[i] /= 2;
for (int i=0;i<=m;i++)
printf("%lld\n",sum[i]);
}
int main()
{
scanf("%d%d",&n,&m);
if (m>10) solve_small_n();
else solve_small_m();
return 0;
}
T3
问题 C: 分配
时间限制: 1 Sec 内存限制: 128 MB
题目描述
输入
输出
样例输入
3 0
1
1
3 1
1
1
样例输出
7
0
3
7
提示