比赛链接:
http://codeforces.com/gym/100676
题目链接:
A. Relational Operator
直接模拟,复杂度O(1)。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
int main()
{
int T;
scanf("%d",&T);
int a,b;
char c[5];
while(T--)
{
scanf("%d%s%d",&a,c,&b);
if(strlen(c)==1)
{
if(c[0]=='<')printf("%s\n",(a<b ? "true" : "false"));
else printf("%s\n",(a>b ? "true" : "false"));
}
else
{
if(c[0]=='!')printf("%s\n",(a!=b ? "true" : "false"));
else if(c[0]=='=')printf("%s\n",(a==b ? "true" : "false"));
else if(c[0]=='<')printf("%s\n",(a<=b ? "true" : "false"));
else printf("%s\n",(a>=b ? "true" : "false"));
}
}
return 0;
}
B. Three Angles
判断三个角度是否均为正且和为180即可,复杂度O(1)。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
int main()
{
int T;
scanf("%d",&T);
int a,b,c;
while(T--)
{
scanf("%d%d%d",&a,&b,&c);
printf("%s\n",(a>0 && b>0 && c>0 && a+b+c==180 ? "YES" : "NO"));
}
return 0;
}
C. Memory is Full
贪心,先移除占用内存较大的软件,复杂度O(nlogn)。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int a[105];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int k,m,n;
scanf("%d%d%d",&k,&m,&n);
int sum=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
int emp=k-sum;
if(emp>=m)
{
printf("0\n");
continue;
}
sort(a+1,a+n+1,greater<int>());
for(int i=1;i<=n;i++)
{
emp+=a[i];
if(emp>=m)
{
printf("%d\n",i);
break;
}
}
}
return 0;
}
D. Sudoku
直接模拟,复杂度O(1)。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
char s[15][15];
bool vis[15];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
for(int i=0;i<9;i++)scanf("%s",s[i]);
bool isok=1;
for(int i=0;i<9;i++)
{
bool flag=1;
memset(vis,0,sizeof(vis));
for(int j=0;j<9;j++)vis[s[i][j]-'1']=1;
for(int j=0;j<9;j++)flag&=vis[j];
isok&=flag;
}
for(int i=0;i<9;i++)
{
bool flag=1;
memset(vis,0,sizeof(vis));
for(int j=0;j<9;j++)vis[s[j][i]-'1']=1;
for(int j=0;j<9;j++)flag&=vis[j];
isok&=flag;
}
for(int i=0;i<9;i+=3)
for(int j=0;j<9;j+=3)
{
memset(vis,0,sizeof(vis));
for(int p=i;p<i+3;p++)
for(int q=j;q<j+3;q++)
vis[s[p][q]-'1']=1;
bool flag=1;
for(int p=0;p<9;p++)flag&=vis[p];
isok&=flag;
}
printf("%s\n",(isok ? "Valid" : "Invalid"));
}
return 0;
}
E. Time Limit Exceeded?
记下每个数出现的次数,维护前缀和后可以O(1)计算每个数作为较小数时的贡献,复杂度O(n)。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
int cnt[10005],pre[10005];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
int in;
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++)
{
scanf("%d",&in);
cnt[in]++;
}
for(int i=1;i<=10000;i++)pre[i]=pre[i-1]+cnt[i];
int ans=0;
for(int i=1;i<=10000;i++)
{
ans+=cnt[i]*(cnt[i]-1)/2;
ans+=cnt[i]*(pre[min(10000,i+31)]-pre[i]);
}
printf("%d\n",ans);
}
return 0;
}
F. Palindrome
若s[i]与s[j]相同,则将s[i]与s[j]合并到同一集合中,并选取集合的代表元素,可以利用并查集维护,
在选取代表元素时,若集合中只有"?",则选"?"为代表元素,否则任意选取一个不为"?"的字符,
完成合并过程后,逐个检查元素及其代表元素是否一致,并统计元素全为"?"的集合个数,复杂度O(nlogn)。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
const int MAXN=50005;
const int Mod=1000000007;
int fast_pow(int a,int k)
{
int res=1;
while(k>0)
{
if(k&1)res=1LL*res*a%Mod;
a=1LL*a*a%Mod;
k>>=1;
}
return res;
}
char s[MAXN];
int p[MAXN];
bool vis[MAXN];
void Init(int n)
{
for(int i=0;i<n;i++)p[i]=i;
}
int Find(int x)
{
return x==p[x] ? x : p[x]=Find(p[x]);
}
void Union(int x,int y)
{
x=Find(x);
y=Find(y);
if(x==y)return;
if(s[x]=='?')p[x]=y;
else p[y]=x;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
scanf("%s",s);
Init(n);
for(int i=0;i<n/2;i++)
Union(i,n-1-i);
int x,y;
while(m--)
{
scanf("%d%d",&x,&y);
Union(x-1,y-1);
}
bool isok=1;
int cnt=0;
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
{
int t=Find(i);
if(s[t]=='?')
{
if(!vis[t])
{
vis[t]=1;
cnt++;
}
}
else isok&=(s[t]==s[i] || s[i]=='?');
}
if(isok)printf("%d\n",fast_pow(26,cnt));
else printf("0\n");
}
return 0;
}
G. Training Camp
状压dp,用dp[s]表示选取了s集合的最大收益,
根据拓扑序检验状态合法性并进行转移即可,复杂度O(n*2^n)。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<string>
#include<vector>
#include<map>
using namespace std;
map<string,int>mp;
string s[25];
int w[25],dp[1<<18];
vector<pair<int,int> >e;
bool used[25],in[25];
void init()
{
e.clear();
mp.clear();
}
int main()
{
ios::sync_with_stdio(false);
stringstream ss;
int T;
cin>>T;
while(T--)
{
int n,m;
cin>>n>>m;
string str;
getline(cin,str);
init();
for(int i=1;i<=n;i++)
{
w[i]=0;
getline(cin,str);
ss.clear();
ss.str(str);
string name="",word="";
while(ss>>word)
{
if(word[0]>='0' && word[0]<='9')
for(int j=0;j<word.size();j++)
w[i]=w[i]*10+word[j]-'0';
else name+=word+" ";
}
mp[name]=i;
}
/*
for(int i=1;i<=n;i++)
cout<<s[i]<<" "<<w[i]<<endl;
*/
for(int i=1;i<=m;i++)
{
getline(cin,str);
ss.clear();
ss.str(str);
string name="",word="";
int st,ed;
while(ss>>word)
{
if(word[0]=='-')
{
st=mp[name];
name.clear();
}
else name+=word+" ";
}
ed=mp[name];
e.push_back(make_pair(st,ed));
}
memset(dp,0,sizeof(dp));
for(int mask=0;mask<(1<<n);mask++)
{
memset(used,0,sizeof(used));
int day=1;
for(int i=0;i<n;i++)
if(mask&(1<<i))
{
day++;
used[i+1]=1;
}
bool isok=1;
for(int i=0;i<e.size();i++)
if(!used[e[i].first] && used[e[i].second])
{
isok=0;
break;
}
if(!isok)continue;
memset(in,0,sizeof(in));
for(int i=0;i<e.size();i++)
if(!used[e[i].first])
in[e[i].second]=1;
for(int i=0;i<n;i++)
if(!used[i+1] && !in[i+1])
dp[mask|(1<<i)]=max(dp[mask|(1<<i)],dp[mask]+day*w[i+1]);
}
cout<<dp[(1<<n)-1]<<endl;
}
return 0;
}
H. Capital City
双连通分量缩点,对得到的树进行两次bfs得到直径,然后枚举直径上的点求出重心,
考虑到可能有重边以及自环,需要进行去重,
去重时利用并查集维护,如果两个点之间有多条路径,则将这两个点合并为一个点,
由于要输出最小的标号,还需要选取每个集合中标号最小的点作为代表元素,复杂度O(nlogn+mlogm)。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<set>
#include<queue>
#include<stack>
using namespace std;
typedef long long ll;
const int MAXN=100005;
const int MAXM=400005;
const int INF=0x3f3f3f3f;
//BCC
struct Edge
{
int to,next,cost;
bool cut;
}edge[MAXM];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Get[MAXN];
int Index,top;
int block;
bool Instack[MAXN];
int bridge;
void addedge(int u,int v,int cost)
{
edge[tot].to=v;
edge[tot].next=head[u];
edge[tot].cut=0;
edge[tot].cost=cost;
head[u]=tot++;
}
void Tarjan(int u,int pre)
{
int v;
Low[u]=DFN[u]=++Index;
Stack[top++]=u;
Instack[u]=1;
for(int i=head[u];i!=-1;i=edge[i].next)
{
v=edge[i].to;
if(v==pre)continue;
if(!DFN[v])
{
Tarjan(v,u);
if(Low[u]>Low[v])Low[u]=Low[v];
if(Low[v]>DFN[u])
{
bridge++;
edge[i].cut=1;
edge[i^1].cut=1;
}
}
else if(Instack[v] && Low[u]>DFN[v])
Low[u]=DFN[v];
}
if(Low[u]==DFN[u])
{
block++;
do
{
v=Stack[--top];
Instack[v]=0;
Belong[v]=block;
}
while(v!=u);
}
}
void init()
{
tot=0;
memset(head,-1,sizeof(head));
}
void get_BCC(int n)
{
memset(DFN,0,sizeof(DFN));
memset(Instack,0,sizeof(Instack));
Index=top=block=bridge=0;
Tarjan(1,0);
memset(Get,INF,sizeof(Get));
for(int i=1;i<=n;i++)
Get[Belong[i]]=min(Get[Belong[i]],i);
}
//DSU
int p[MAXN];
void DSU_Init(int n)
{
for(int i=1;i<=n;i++)p[i]=i;
}
int DSU_Find(int x)
{
return x==p[x] ? x : p[x]=DSU_Find(p[x]);
}
void DSU_Union(int x,int y)
{
x=DSU_Find(x);
y=DSU_Find(y);
if(x==y)return;
p[x]=y;
}
void DSU_Compress(int n)
{
for(int i=1;i<=n;i++)p[i]=DSU_Find(i);
}
//InputData
struct Input
{
int u,v,cost;
Input(){}
Input(int _u,int _v,int _cost)
{
if(_u>_v)swap(_u,_v);
u=_u;
v=_v;
cost=_cost;
}
bool operator < (const Input &t)const
{
return v==t.v ? u<t.u : v<t.v;
}
};
set<Input>s;
int vis[MAXN];
int Stand[MAXN];
//Tree
vector<pair<int,int> >e[MAXN];
void Prepare(int n)
{
for(int i=1;i<=n;i++)e[i].clear();
for(int i=1;i<=n;i++)
for(int j=head[i];j!=-1;j=edge[j].next)
if(edge[j].cut)
{
e[Belong[i]].push_back(make_pair(Belong[edge[j].to],edge[j].cost));
e[Belong[edge[j].to]].push_back(make_pair(Belong[i],edge[j].cost));
}
}
pair<int,int> pre[MAXN];
ll dis[MAXN];
int BFS(int st)
{
for(int i=1;i<=block;i++)dis[i]=(1LL<<62)-1;
queue<int>q;
q.push(st);
pre[st].first=pre[st].second=-1;
dis[st]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=0;i<e[u].size();i++)
{
int v=e[u][i].first;
int c=e[u][i].second;
if(dis[v]>dis[u]+c)
{
q.push(v);
dis[v]=dis[u]+c;
pre[v]=make_pair(u,c);
}
}
}
int loc=st;
ll Max=0;
for(int i=1;i<=block;i++)
if(dis[i]>Max)
{
loc=i;
Max=dis[i];
}
return loc;
}
//Main
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
init();
int n,m;
scanf("%d%d",&n,&m);
DSU_Init(n);
s.clear();
int a,b,c;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
if(a==b)continue;
Input t=Input(DSU_Find(a),DSU_Find(b),c);
if(s.find(t)==s.end())s.insert(t);
else DSU_Union(a,b);
}
DSU_Compress(n);
int cnt=0;
memset(Stand,INF,sizeof(Stand));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
int t=DSU_Find(i);
if(!vis[t])vis[t]=++cnt;
Stand[vis[t]]=min(Stand[vis[t]],i);
}
set<Input>::iterator itr;
for(itr=s.begin();itr!=s.end();itr++)
{
Input t=*itr;
int t1=DSU_Find(t.u);
int t2=DSU_Find(t.v);
if(t1==t2)continue;
else
{
addedge(vis[t1],vis[t2],t.cost);
addedge(vis[t2],vis[t1],t.cost);
}
}
get_BCC(cnt);
Prepare(cnt);
int end1=BFS(1);
int end2=BFS(end1);
ll len=dis[end2];
stack<pair<int,ll> >sst;
ll now=0;
sst.push(make_pair(end2,max(now,len-now)));
for(int i=end2;i!=end1 && i!=-1;i=pre[i].first)
{
now+=pre[i].second;
ll t=max(now,len-now);
while(!sst.empty() && t<sst.top().second)sst.pop();
if(sst.empty() || t==sst.top().second)sst.push(make_pair(pre[i].first,t));
}
int ans_loc=INF;
ll ans_pat=sst.top().second;
while(!sst.empty())
{
ans_loc=min(ans_loc,Stand[Get[sst.top().first]]);
sst.pop();
}
printf("%d %I64d\n",ans_loc,ans_pat);
}
return 0;
}