题目:
A: Multiplication Dilemma
我们先把所有数都拆解成 (a+b+c…+d) 的形式,然后利用乘法分配律去掉括号即可.
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
long long a[2][15];
int getnum(int x,int num) {
int len =0;
int time = 1;
while(x) {
if(x%10) {
a[num][len]=time*(x%10);
len ++;
}
x /=10;
time *= 10;
}
return len;
}
int main() {
int t;
scanf("%d",&t);
while(t--) {
int c,b;
scanf("%d%d",&c,&b);
int len1 = getnum(c,0);
int len2 = getnum(b,1);
for(int i=0;i<len1;i++) {
for(int j=0;j<len2;j++) {
if(i == 0 && j == 0) printf("%lld x %lld", a[0][i],a[1][j]);
else printf(" + %lld x %lld",a[0][i],a[1][j]);
}
}
printf("\n");
}
return 0;
}
B: Updating the Tree
对于某点有两个三个或三个以上的分支,不可能构成.
对于有两个分支的结点,其父亲节点及其祖先也是不能构成的.
那么现在还剩一个分支,和两个分支的情况.
很明显我们可以把这两种情况看成是一条链,那么该条链的最小修改次数就等于链上每个数减去一个 自增(减)的标记index 后,链的总长减去权值中出现最多次的次数.
很明显我们可以搞一个权值线段树,每次查询最大值即可.
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int Pi = 130005;
const int maxn =1e5+7;
const int Maxn = 350050;
int n,e;
int a[maxn];
int head[maxn];
int edge[maxn<<1];
int nex[maxn<<1];
int ans[maxn];
int type[maxn];
int sz[maxn];
int tr[2][Maxn<<2];
int lazy[2][Maxn<<2];
void add(int l,int r) {
edge[++e] = r;
nex[e]=head[l];
head[l]=e;
}
void pushdown(int x,int num) {
if(lazy[x][num]==0) return ;
lazy[x][num<<1] = lazy[x][num<<1|1] = 1;
tr[x][num<<1] = tr[x][num<<1|1] = 0;
lazy[x][num] = 0;
return ;
}
void pushup(int x,int num) {tr[x][num] = max(tr[x][num<<1],tr[x][num<<1|1]);}
void build(int x,int l,int r,int num) {
if(l==r) {
tr[x][num]=0;
return ;
}
int mid = (l+r) >>1;
build(x,l,mid,num<<1);
build(x,mid+1,r,num<<1|1);
pushup(x,num);
}
void modify(int x,int l,int r,int num,int pos,int op) {
if(op==1) tr[x][num]=0,lazy[x][num]=1;
if(pos==-1) return ;
if(pos == l && pos == r) {
tr[x][num]++;
return ;
}
// printf("%d %d %d\n",l,r,num);
int mid = (l+r) >>1;
pushdown(x,num);
if(pos<=mid) modify(x,l,mid,num<<1,pos,op);
if(mid< pos) modify(x,mid+1,r,num<<1|1,pos,op);
pushup(x,num);
}
bool dfs(int u,int f) {
int sum = 0;
bool flag=true;
sz[u] =1;
for(int i=head[u];i;i=nex[i]) {
int v = edge[i];
if(v==f) continue;
sum++;
if(!dfs(v,u)) flag=false;
sz[u]+=sz[v];
}
if(flag == true && sum <= 1) type[u]=1;
else if(!flag || sum >2) type[u]=0;
else type[u]=2;
return flag && sum <=1;
}
int index;
int T;
void getans(int u,int f) {
if(type[u] == 0) ans[u] = -1;
bool leaf = true;
if(type[u] == 2) T = u;
modify(0,1,Maxn,1,a[u]+index+Pi,0);
modify(1,1,Maxn,1,a[u]-index+Pi,0);
index++;
//printf(" %d %d\n",u,index);
for(int i=head[u];i;i=nex[i]) {
int v = edge[i];
if(v==f) continue;
getans(v,u);
if(type[u] == 2 && leaf == true) {
modify(0,1,Maxn,1,a[u]+index+Pi,0);
modify(1,1,Maxn,1,a[u]-index+Pi,0);
index++;
}
leaf=false;
}
if(type[u] != 2 && type[u] != 0) {
if(!leaf) {
modify(0,1,Maxn,1,a[u]+index+Pi,0);
modify(1,1,Maxn,1,a[u]-index+Pi,0);
}
if(leaf) {
ans[T] = max(tr[0][1],tr[1][1]);
modify(0,1,Maxn,1,-1,1);
modify(1,1,Maxn,1,-1,1);
index = 0;
modify(0,1,Maxn,1,a[u]+index+Pi,0);
modify(1,1,Maxn,1,a[u]-index+Pi,0);
}
ans[u] = max(tr[0][1],tr[1][1]);
index++;
}
else {
modify(0,1,Maxn,1,-1,1);
modify(1,1,Maxn,1,-1,1);
}
if(T==u) T= 0;
return ;
}
int main() {
int t;
scanf("%d",&t);
build(0,1,Maxn,1);
build(1,1,Maxn,1);
while(t--) {
e = 0;
scanf("%d",&n);
memset(head,0,sizeof(head));
memset(ans,0,sizeof(ans));
index = 0;
T =0;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=0;i<n-1;i++) {
int l,r;
scanf("%d%d",&l,&r);
add(l,r);
add(r,l);
}
dfs(1,0);
modify(0,1,Maxn,1,-1,1);
modify(1,1,Maxn,1,-1,1);
getans(1,0);
for(int i=1;i<=n;i++){
printf("%d",ans[i] == -1? -1:sz[i]-ans[i]);
if(i!=n) printf(" ");
else printf("\n");
}
}
return 0;
}
C: Shortest Path!
联想到光的反射,我们每次找对称点就可以了…
比赛的时候被队友给秒了…
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
int t;
long double a,b,c,x;
long double getnode(long double x,long double y) {
return 1.0*(b+c-x)*(a-y) / (b+2*c-x);
}
int main() {
scanf("%d",&t);
while(t--) {
cin>>a>>b>>c>>x;
long double d =getnode(1.0*0,1.0*0);
long double ans = (sqrt(d*d+(b+c)*(b+c)) + sqrt((a-d)*(a-d)+c*c));
long double d2 = getnode(1.0*b*x/100,1.0*a*x/100);
ans += (sqrt( 1.0*(b+c-1.0*b*x/100)*(b+c-1.0*b*x/100) + d2*d2 ) + sqrt( c*c + (a-1.0*a*x/100-d2) *(a-1.0*a*x/100-d2) ));
ans += sqrt(1.0*b*b*x*x/10000+1.0*a*a*x*x/10000);
printf("%.10lf\n",ans);
}
return 0;
}
D: Wooden Fence
签到题.
直接n,x,y比较即可.
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
int t;
long long a,b,c;
int main() {
scanf("%d",&t);
while(t--) {
cin>>a>>b>>c;
b = min(b-1,c);
if(a>b*2+1) cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
return 0;
}
E: Stupid Submissions
看完题目感觉就是说的我没错了
题目还是直接模拟就可以了,用个int 存当前已经知道了前多少组数据,每次看是不是小数据和已知数据范围内即可.
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn = 1e4+7;
int n,m,k;
int vis[maxn];
int main() {
int t;
scanf("%d",&t);
while(t--) {
scanf("%d%d%d",&n,&k,&m);
for(int i=1;i<=n;i++) {
char s;
scanf(" %c",&s);
if(s=='S') vis[i] = 0;
if(s=='B') vis[i] = 1;
}
int ans = 0;
while(k--) {
char s;
scanf(" %c",&s);
if(s=='W') {
int d;
scanf("%d",&d);
if(d<=m && vis[d] == 0) ans++;
m = max(d,m);
}
else m = n;
}
printf("%d\n",ans);
}
return 0;
}
F: I’m Bored!
分情况讨论.
最大为 1 的情况.
最大大于 1 并且没有 1的情况
最大大于 1 没切 有1的情况
最大为0的情况
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 50;
int ans1=0,ans2=0;
int vis[maxn];
int main() {
int t;
scanf("%d",&t);
while(t--) {
int flag1 = 1;
int flag2 = 1;
memset(vis,0,sizeof(vis));
for(int i=0;i<26;i++) {
scanf("%d",&vis[i]);
if(vis[i]==1) flag1 = 0;
if(vis[i]>=2) flag2 = 0;
}
if(flag2 && flag1) printf("%d %d\n",0,0);
else if(!flag1 && flag2) {
int sum = 0;
for(int i=0;i<26;i++) {
if(vis[i] != 0) sum++;
}
printf("%d %d\n",1,sum);
}
else if(!flag2 && flag1) {
int maxs= 1e9+7;
int sum1=0,sum2=0;
for(int i=0;i<26;i++) {
if(vis[i] == 1) sum2++;
if(vis[i] >= 2) maxs=min(maxs,vis[i]),sum1++;
}
printf("%d %d\n",sum1*2,maxs/2);
}
else {
int maxs= 1e9+7;
int sum1=0,sum2=0;
for(int i=0;i<26;i++) {
if(vis[i] == 1) sum2++;
if(vis[i] >= 2) maxs=min(maxs,vis[i]),sum1++;
}
printf("%d %d\n",sum1*2+1,min(maxs/2,sum2));
}
}
return 0;
}
G: Minimax
经典的dp,我们先用 O(4 * n * m) 的复杂度求出以上下左右四个顶点为一个顶点的矩阵的最大值.
然后枚举所有可能的切割交点,更新最大值即可.
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
int n,m,k;
int a[510][510];
int Max[4][510][510];
int ab(int x,int y) {
int Maxs=0;
int Mins=1e9+7;
Maxs = max(Maxs,Max[0][x-1][y-1]);
Mins = min(Mins,Max[0][x-1][y-1]);
Maxs = max(Maxs,Max[1][x-1][y+1]);
Mins = min(Mins,Max[1][x-1][y+1]);
Maxs = max(Maxs,Max[2][x+1][y-1]);
Mins = min(Mins,Max[2][x+1][y-1]);
Maxs = max(Maxs,Max[3][x+1][y+1]);
Mins = min(Mins,Max[3][x+1][y+1]);
return Maxs - Mins;
}
int main() {
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
scanf("%d",&a[i][j]);
Max[0][i][j] = a[i][j];
if(i!=1) Max[0][i][j] = max(Max[0][i][j],Max[0][i-1][j]);
if(j!=1) Max[0][i][j] = max(Max[0][i][j],Max[0][i][j-1]);
}
}
for(int i=1;i<=n;i++) {
for(int j=m;j>=1;j--) {
Max[1][i][j] = a[i][j];
if(i!=1) Max[1][i][j] = max(Max[1][i][j],Max[1][i-1][j]);
if(j!=m) Max[1][i][j] = max(Max[1][i][j],Max[1][i][j+1]);
}
}
for(int i=n;i>=1;i--) {
for(int j=1;j<=m;j++) {
Max[2][i][j] = a[i][j];
if(i!=n) Max[2][i][j] = max(Max[2][i][j],Max[2][i+1][j]);
if(j!=1) Max[2][i][j] = max(Max[2][i][j],Max[2][i][j-1]);
}
}
for(int i=n;i>=1;i--) {
for(int j=m;j>=1;j--) {
Max[3][i][j] = a[i][j];
if(i!=n) Max[3][i][j] = max(Max[3][i][j],Max[3][i+1][j]);
if(j!=m) Max[3][i][j] = max(Max[3][i][j],Max[3][i][j+1]);
}
}
int ans = 1e9+7;
for(int i =2;i<n;i++) {
for(int j=2;j<m;j++) {
ans = min(ans,ab(i,j));
}
}
printf("%d\n",ans);
}
return 0;
}
H: Beautiful Substrings
暴力枚举出所有合理的开头与结尾的组合,然后在第二个字符串里面用后缀和存每个字符出现的次数,暴力搞一下就可以了.
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
int n,m,k;
char s1[100050];
char s2[100050];
int vis[30][30];
long long pre[30];
long long ans =0;
int main() {
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d%d%s%s",&n,&m,&k,s1,s2);
memset(vis,0,sizeof(vis));
memset(pre,0,sizeof(pre));
ans = 0;
for(int i=0;i+k-1<n;i++) {
int d= s1[i]-'a';
int t = s1[i+k-1]-'a';
vis[d][t] =1;
}
for(int i = m-1;i>=0;i--) {
int d = s2[i]-'a';
pre[d]++;
for(int j=0;j<26;j++) {
if(vis[d][j] == 0) continue;
ans += pre[j];
}
}
printf("%lld\n",ans);
}
return 0;
}
I: Secret Project
留个坑.
比赛的时候我的两位神仙队友一个找规律一个证明都搞出了…
J: Even Numbers
数学题
留个坑,这种东西一般都交给队友了.
J: Cyclic Shift
只能挪一位,所以直接模拟就可以了
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
string s1,s2;
int main() {
int t;
cin>>t;
while(t--) {
int n;
cin>>n;
cin>>s1>>s2;
string ss1,ss2;
int k =0;
int ls,rs;
for(int i=0;i<n;i++) {
if(s1[i] == s2[i]) continue;
ss1+=s1[i];
ss2+=s2[i];
}
int len=ss1.size();
if(len == 0) {
cout<<"YES"<<endl;
continue;
}
if(ss1[0] != ss2[len-1]) cout<<"NO"<<endl;
else {
int l=1,r=0;
for(int i=0;i<len-1;i++) {
if(ss1[l++] != ss2[r++] ) {
cout<<"NO"<<endl;
break;
}
if(i==len-2) cout<<"YES"<<endl;
}
}
}
return 0;
}