第一次Codeforces.做出三题,但是第二题,有个细节没考虑到。Rating:1500+151=1651,于是下次继续Div2吧。>_<!
A:
题目给出平行六面体的连接一个顶点的三个面的面积,输出这个12条棱的和。
只要枚举下一条边,求出另外的两条边就行了。
#include<cstdio>
#include<iostream>
#include<cstdlib>
using namespace std;
int a,b,c;
bool work(int a,int b,int c)
{
int j,k;
for (int i = 1;i*i<=a;++i)
if (a % i == 0)
{
j = a / i;
if (b % j == 0)
{
k = b / j;
if (c == i * k )
{
cout << (i+j+k)*4 << endl;
return 1;
}
}
}
return 0;
}
int main()
{
cin >> a >> b >> c;
if (work(a,b,c) || work(a,c,b) || work(b,a,c)
|| work(b,c,a) || work(c,a,b) || work(c,b,a) )
{
return 0;
}
return 0;
}
B:
给数组a,包含n个元素,人物是找到inclusion segment[l,r].使得,al al+1 … ar,包含了正好k个不同的数字。Definclusion : if there is no segment [x, y]satisfying the property and less thenm inlength, such that 1 ≤ l ≤ x ≤ y ≤ r ≤ n然后r-l不一定要最小。
直接上代码:
#include<iostream>
#include<cstdio>
using namespace std;
int n,k,d,cnt,left = 1;;
int a[200000];
int flag[200000];
int initial = -1;
int main()
{
cin >> n >> k;
cnt = 0;
for (int i = 1;i<=100000;++i) flag[i] == 0;
for (int i = 0;i<n;++i)
{
scanf("%d",&d);
a[i] = d;
if (flag[d] == 0)
{
++cnt;
++flag[d];
if (cnt == k)
{
int l = 0;
while (l+1<i && flag[a[l]]>1) { --flag[a[l]];++l; }
printf("%d %d\n",l+1,i+1);
return 0;
}
}else ++flag[d];
}
printf("-1 -1\n");
return 0;
}
C:
定义括号字符串为包含[] & () 的字符串。然后题目费劲地想表达的是找到一个最大的满足匹配的子串,使得”[”的数目最多,并输出这个子串。
用栈来做,遇到左括号压栈,遇到右括号弹出。然后用个计数器,累加,每当出现不匹配的情况,就清空计数器,很容易顺便求出最大值和这个子串。
但是不能处理这种情况([]([]
为了处理这种情况,我把[]的这个计数器统计到(只有当有右括号匹配(时,[]才会被统计。
实现起来只是添加了一个和栈内元素对应的数组来记录计数。
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
string s;
int stack[200000];
int value[200000];
int n;
int transfer(char c)
{
if (c == '(') return 2;
if (c == '[') return 1;
if (c == ']') return -1;
if (c == ')') return -2;
}
int top = 0;
int bj = 0;
int main()
{
cin >> s;
n = s.size();
int now = 0,ans = 0;
for (int i = 0;i<s.size();++i)
{
if (transfer(s[i]) >0 )
{
stack[top] = transfer((s[i]));
value[top] = now;
now = 0;
++top;
} else{
if (top == 0 || transfer(s[i]) + stack[top-1] != 0)
{
top = 0;
now = 0;
continue;
}
--top;
now += value[top];
if (transfer(s[i]) == -1) ++now;
if (now > ans )
{
ans = now;
bj = i;
}
}
}
cout << ans << endl;
int rs = 0,ls = 0,lc = 0,rc = 0;
if (ans != 0)
{
int tp = bj;
while (tp>=0)
{
if (s[tp] == ']') ++ rs;
if (s[tp] == '[') ++ ls;
if (s[tp] == '(') ++ lc;
if (s[tp] == ')') ++ rc;
if (ls == ans && rs == ans && lc == rc)
{
cout << string(s,tp,bj-tp+1) << endl;
return 0;
}
--tp;
}
}
return 0;
}
D:
得到两个字串S和T,考虑一类子串X=sk1sk2…skn.满足k1<k2<…<kn.
判断是否对于所有的I, X=sk1sk2…skn,X=T 并且 Kj=i.
计算出Left[i] i=0..T.size(),表示S中的所有X中能够匹配T[i]的极左。
同理计算出Right[i]表示能够匹配T[i]的极右。然后题目就变成了一些线段能否覆盖所有线段。
可以用类似括号匹配的方法来做。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
using namespace std;
const int N = 200005;
string S,T;
int occ[256];
int markL[N],markR[N];
int main()
{
cin >> S >> T;
int l,r;
r = 0;
for (l = 0;l<S.size();++l)
{
if (r<T.size() && S[l] == T[r]) markL[l]++, ++r;
}
if (r<T.size())
{
puts("No");
return 0;
}
r = T.size()-1;
for ( l = S.size()-1;l>=0;--l)
{
if (r>=0 && S[l] == T[r]) markR[l]-- , --r;
}
// for (int i = 0;i<S.size();++i) cout << markL[i] << " " << markR[i] << endl;
for (int i = 0;i<S.size();++i)
{
occ[S[i]] += markL[i];
if (occ[S[i]] == 0)
{
puts("No");
return 0;
}
occ[S[i]] += markR[i];
}
puts("Yes");
return 0;
}
E:
给出一个数组n元数组a。我们队数组a进行k次操作。操作定义如下。
1、
2、把s赋给a。
输出k次操作后的数组a。
因为(1 ≤ n ≤ 2000,0 ≤ k ≤ 109)所以不能用矩阵乘法(n太大了).
推出公式:
要推出这个公式也不难,先不要考虑a,然后观察操作后Si的值(这个值有aj的系数组成).
#include<iostream>
#include<cstdio>
using namespace std;
#define LL long long
const LL MOD = 1000000007;
//const LL MOD = 7;
LL myDiv(int x)
{
LL res = 1;
LL tmp = x;
int y = MOD-2;
while (y>0)
{
if (y % 2 == 1)
{
res *= tmp;
res %= MOD;
}
y/= 2;
tmp *= tmp;
tmp %= MOD;
}
return res;
}
LL getC(int n,int k)
{
LL res = 1;
for (int i = 1;i<=k;++i)
{
res = res * (n-i+1);
res %= MOD;
res = res * myDiv(i);
res %= MOD;
}
return res;
}
int n,k;
LL ar[2005],Ans[2005];
int C[2005];
int main()
{
cin >> n >> k ;
for (int i = 0;i<n;++i)
scanf("%d",&ar[i]);
if (k==0)
{
for (int i = 0;i<n;++i) Ans[i] = ar[i];
} else {
for (int i = 0;i<=n;++i)
{
C[i] = getC(k-1+i,i);
// cout << i << " " << C[i] << endl;
}
for (int i = 0;i<n;++i)
{
Ans[i] = 0;
for (int j = 0;j<=i;++j)
{
Ans[i] += ar[j] * C[i-j];
// cout << C[i-j] << endl;
Ans[i] %= MOD;
}
// printf("\n");
}
}
for (int i = 0;i<n-1;++i)
{
printf("%d ",Ans[i]);
}
printf("%d\n",Ans[n-1]);
return 0;
}