比赛链接:
http://codeforces.com/gym/100676
题目链接:
http://codeforces.com/gym/100676/attachments/download/3333/acm-arabella-collegiate-programming-contest-en.pdf
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; }
判断三个角度是否均为正且和为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; }
贪心,先移除占用内存较大的软件,复杂度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; }
直接模拟,复杂度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; }
记下每个数出现的次数,维护前缀和后可以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; }
若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; }
状压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; }
双连通分量缩点,对得到的树进行两次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; }