#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=1000010;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000009;
const ll INF=10000000010;
typedef unsigned long long ull;
char s[10];
int a[50];
int main()
{
int i,n,p;
ll sum=0,ans=0;
scanf("%d%d", &n, &p);
for (i=1;i<=n;i++) {
scanf("%s", s);
if (strlen(s)>4) a[i]=1;
else a[i]=0;
}
for (i=n;i>0;i--)
if (a[i]) sum=sum*2+1;
else sum<<=1;
for (i=1;i<=n;i++)
if (sum&1) {
ans+=sum/2*p+p/2;sum>>=1;
} else {
ans+=sum/2*p;sum>>=1;
}
printf("%I64d\n", ans);
return 0;
}
problemB:给定一个长度为n的只含'A'和'B'的字符串,然后给出这n个位置的价值p[i]。最多进行一次以下操作:选择一个字符串的前缀或后缀,使得这个子串全部翻转(A->B,B->A)。求最后在所有字符'B'对于位置的价值之和的最大值。O(n)
分析:正反维护下前缀和即可。
代码:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=500010;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
const ll INF=10000000010;
typedef unsigned long long ull;
char s[N];
ll y[N],p[N],sum[N];
int main()
{
int i,n;
ll ans=0;
scanf("%d", &n);
for (i=1;i<=n;i++) scanf("%I64d", &p[i]);
scanf("%s", s);
y[0]=sum[0]=0;
for (i=1;i<=n;i++)
if (s[i-1]=='B') {
y[i]=y[i-1]+p[i];sum[i]=sum[i-1]-p[i];
} else {
y[i]=y[i-1];sum[i]=sum[i-1]+p[i];
}
ans=y[n];
for (i=1;i<=n;i++) {
ans=max(ans,y[n]+sum[i]);
ans=max(ans,y[n]+sum[n]-sum[i-1]);
}
printf("%I64d\n", ans);
return 0;
}
problemC:给定n个字符串,将这n个字符串接成一个长串,求字典序最小的长串。
分析:假设s[i],s[j]相邻且所有字符串除了s[i],s[j]都已经排好了,判断i在前好还是j在前好,判断一下s[i]+s[j]<s[j]+s[i]即可。排序。O(50*nlogn)
代码:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=50010;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000000;
const ll INF=10000000010;
typedef unsigned long long ull;
string s[N];
int cmd(string a,string b) {
string ab=a+b;
string ba=b+a;
return ab<ba;
}
int main()
{
int i,n;
scanf("%d", &n);
for (i=1;i<=n;i++) cin>>s[i];
sort(s+1,s+n+1,cmd);
for (i=1;i<=n;i++) cout<<s[i];
cout<<endl;
return 0;
}
problemD:给定n,m,然后给定n个数a[i]。要求选出最多个数的a[i]同时使得LCM(a[i])<=m。多组解时输出LCM最小的那组。
分析:用数组统计下即可,然后从后往前用数x去更新x的倍数。O(n+mlogm)
代码:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=1000010;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
const ll INF=10000000010;
typedef unsigned long long ull;
int a[N],dp[N];
int main()
{
int i,j,n,m,w,mx=0;
scanf("%d%d", &n, &m);
memset(dp,0,sizeof(dp));
for (i=1;i<=n;i++) {
scanf("%d", &a[i]);
if (a[i]<=m) dp[a[i]]++;
}
for (i=m;i>0;i--)
if (dp[i]) {
for (j=2*i;j<=m;j+=i) dp[j]+=dp[i];
}
for (i=1;i<=m;i++)
if (dp[i]>mx) { mx=dp[i];w=i; }
if (!mx) printf("1 0\n");
else {
printf("%d %d\n", w, mx);
for (i=1;i<=n;i++)
if (w%a[i]==0) printf("%d ", i);
printf("\n");
}
return 0;
}
problemE:给定n,k,然后n个数a[i]。求n个数中选k个数加起来能组成多少个不同的数。
分析:用FFT处理。我还不会。下次补。
代码:
problemF:给定一个n*n的矩阵,要求你判断是否满足以下条件:(1)a[i][i]=0。(2)a[i][j]==a[j][i]&&i!=j。(3)对于任意a[i][j]<=max(a[i][k],a[j][k])。
分析:很明显我们要处理的难点在于条件3。我们可以将条件3看成对于任意3个点i,j,k恒成立三角形的一边小于等于另外两边的最大值,然后我们可以将这个条件推到4个点i,j,k,l恒成立a[i][l]<=max(a[i][j],a[j][k],a[k][l]),5个点...。然后我们发现其实就是求一个最小生成树,然后对于任意两点i,j在树上的路径上的最大值x>=a[i][j]。O(n^2logn)
代码:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=2510;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
const ll INF=10000000010;
typedef unsigned long long ull;
struct node {
int u,v,w;
node () {}
node (int u,int v,int w):u(u),v(v),w(w) {}
bool operator < (const node a) const {
return a.w<w;
}
}g;
int q[N],d[N],a[N][N],mx[N][N];
priority_queue<node>Q;
int main()
{
int i,j,n,k=0,bo=1;
scanf("%d", &n);
for (i=1;i<=n;i++)
for (j=1;j<=n;j++) scanf("%d", &a[i][j]);
for (i=1;i<=n;i++)
if (a[i][i]) bo=0;
for (i=1;i<=n;i++)
for (j=1;j<i;j++)
if (a[i][j]!=a[j][i]) bo=0;
if (!bo) printf("NOT MAGIC\n");
else {
memset(q,0,sizeof(q));
memset(mx,0,sizeof(mx));
q[1]=1;d[++k]=1;
for (i=2;i<=n;i++) Q.push(node(1,i,a[1][i]));
while (!Q.empty()) {
if (k>=n) break ;
g=Q.top();Q.pop();
if (q[g.v]) continue ;
q[g.v]=1;d[++k]=g.v;
for (i=1;i<k;i++)
mx[d[i]][g.v]=mx[g.v][d[i]]=max(mx[d[i]][g.u],g.w);
for (i=1;i<=n;i++)
if (!q[i]) Q.push(node(g.v,i,a[g.v][i]));
}
for (i=1;i<=n;i++)
for (j=1;j<i;j++)
if (mx[i][j]<a[i][j]) bo=0;
if (bo) printf("MAGIC\n");
else printf("NOT MAGIC\n");
}
return 0;
}