链接:http://codeforces.com/contest/632
A. Grandma Laura and Apples
题意:n个人买苹果,每个人当前买一半的苹果,每个苹果p(偶数)元,输入half代表当前有偶数个苹果;halfplus代表当前有奇数个苹果,
因为是奇数,所以多的0.5个苹果送给这个人。
分析:逆着算钱,第i次的钱是i+1的两倍,如果是halfplus就加p/2。ans加上这次的钱就好了。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 50
#define Mm 2000005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
int a[Mn];
int main() {
int n,m;
string s;
scanf("%d%d",&n,&m);
ll ans=0,b=0;
for(int i=1;i<=n;i++) {
cin>>s;
if(s[s.size()-1]=='s') {
a[i]=1;
} else {
a[i]=0;
}
}
for(int i=n;i>=1;i--) {
b=b*2;
if(a[i]==1) b+=m/2;
ans+=b;
}
cout<<ans<<endl;;
return 0;
}
B. Alice, Bob, Two Teams
题意:给一个长度为n的数组p和串s,表示有p[i]个s[i],s串只包含‘A’,‘B’。有唯一一次操作,让串前缀或后缀全部反转(A->B,B->A),问B最多为多少。
分析:前后维护前缀和就好了。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 2000010
#define Mm 2000005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
ll q[Mn],a[Mn],b[Mn];
char s[Mn];
int main() {
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf("%I64d",&q[i]);
}
scanf("%s",s+1);
ll ans=0;
for(int i=1;i<=n;i++) {
if(s[i]=='A') {
a[i]+=a[i-1]+q[i];
b[i]=b[i-1];
} else {
b[i]+=b[i-1]+q[i];
a[i]=a[i-1];
}
}
ans=b[n];
for(int i=1;i<=n;i++) {
if(a[i]>b[i]) {
ans=max(ans,a[i]+b[n]-b[i]);
}
}
CLR(a,0);CLR(b,0);
for(int i=n;i>=1;i--) {
if(s[i]=='A') {
a[i]+=a[i+1]+q[i];
b[i]=b[i+1];
} else {
b[i]+=b[i+1]+q[i];
a[i]=a[i+1];
}
}
for(int i=n;i>=1;i--) {
if(a[i]>b[i]) {
ans=max(ans,a[i]+b[1]-b[i]);
}
}
cout<<ans<<endl;
return 0;
}
题意:给你n个字符串,输出这n个串组合成的字符串字典序最小。
分析:直接排序输出是按每个串本身字典序排,整体并不是最小的。由于是要组合后的,所以我们定义排序规则 (a+b)<(b+a)。这样就可以让整体最小了。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 1001000
#define Mm 2000005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
bool cmp(string a,string b) {
return (a+b)<(b+a);
}
string s[Mn];
int main() {
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) {
cin>>s[i];
}
sort(s+1,s+1+n,cmp);
for(int i=1;i<=n;i++) cout<<s[i];
return 0;
}
题意:给出n个数,让你输出l,k,n个数中k个数的LCM,要求k最大的最小l。
分析:由于LCM不超过m(m<10^6),记录每个数的个数,从m到1,枚举这些数的倍数,a[i*j]+=a[i].最后找出最大。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 1000010
#define Mm 2000005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
int a[Mn],b[Mn];
int main() {
int n,m,x;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) {
scanf("%d",&b[i]);
if(b[i]<=m) a[b[i]]++;
}
for(int i=m;i>=1;i--) {
if(a[i]) {
for(int j=2;i*j<=m;j++) {
a[i*j]+=a[i];
}
}
}
int ans=0,pos=0;
for(int i=1;i<=m;i++) {
if(a[i]>ans) {
ans=a[i];
pos=i;
}
}
if(pos) {
cout<<pos<<" "<<ans<<endl;
for(int i=1;i<=n;i++) {
if(pos%b[i]==0) cout<<i<<" ";
}
}else cout<<1<<" "<<0<<endl;
return 0;
}
题意:不会。。。。
分析:
代码:
题意:给你一个n*n的矩阵,要你判断是否满足a[i][j]=0,a[i][j]=a[j][i],对于任意k满足a[i][j]<=max(a[i][k],a[j][k]).
分析: 由于对称,可以最后一个条件转换成a[i][j]<=max(a[i][k],a[k][j]),将矩阵上的a[i][j]看成点i到点j边长为a[i][j]。
然后就可以发现这个条件变成,a[i][j]小于等于i到j路径上的每条边。求个最小生成树。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 2510
#define Mm 2000005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
int vt[Mn*Mn/2];
int a[Mn][Mn],cnt=0,n,pre[Mn];
bool cmp(int x,int y) {
return a[x/n][x%n]<a[y/n][y%n];
}
int find(int x) {
if(x!=pre[x]) return pre[x]=find(pre[x]);
return pre[x];
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
pre[i]=i;
}
for(int i=1;i<=n;i++) {
if(a[i][i]) {printf("NOT MAGIC\n");return 0;}
for(int j=1;j<=n;j++) {
if(a[i][j]!=a[j][i]) {printf("NOT MAGIC\n");return 0;}
if(i>j) vt[cnt++]=i*n+j;
}
}
int k=0;
sort(vt,vt+cnt,cmp);
for(int i=0;i<cnt;i++) {
if(i<cnt&&a[vt[i]/n][vt[i]%n]==a[vt[i+1]/n][vt[i+1]%n]) continue;
for(int j=k;j<=i;j++)
if(find(vt[j]/n)==find(vt[j]%n)) {printf("NOT MAGIC\n");return 0;}
for(int j=k;j<=i;j++) {
int x=find(vt[j]/n);
int y=find(vt[j]%n);
if(x!=y) pre[x]=y;
}
k=i+1;
}
printf("MAGIC\n");
return 0;
}