Codeforces Round #364 (Div. 2)
还是4个1a
记录代码
A
1 //#define txtout 2 //#define debug 3 #include<bits/stdc++.h> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 typedef long long LL; 7 const double pi=acos(-1.0); 8 const double eps=1e-8; 9 const int inf=0x3f3f3f3f; 10 const int M=1e5+10; 11 int n,m; 12 int a[M]; 13 bool v[M]; 14 void solve(){ 15 16 } 17 int main(){ 18 #ifdef txtout 19 freopen("in.txt","r",stdin); 20 freopen("out.txt","w",stdout); 21 #endif // txtout 22 while(~scanf("%d",&n)){ 23 int sum=0; 24 for(int i=1;i<=n;i++){ 25 scanf("%d",&a[i]); 26 sum+=a[i]; 27 v[i]=false; 28 } 29 int avg=sum*2/n; 30 for(int i=1;i<=n;i++){ 31 bool flag=false; 32 for(int j=1;j<=n;j++){ 33 if(v[j]) continue; 34 for(int k=j+1;k<=n;k++){ 35 if(v[k]) continue; 36 if(a[j]+a[k]==avg){ 37 flag=true; 38 printf("%d %d\n",j,k); 39 v[j]=true; 40 v[k]=true; 41 break; 42 } 43 } 44 if(flag) break; 45 } 46 } 47 } 48 return 0; 49 }
B
1 //#define txtout 2 //#define debug 3 #include<bits/stdc++.h> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 typedef long long LL; 7 const double pi=acos(-1.0); 8 const double eps=1e-8; 9 const int inf=0x3f3f3f3f; 10 const int M=1e5+10; 11 int n,m; 12 set<int> sx,sy; 13 int main(){ 14 #ifdef txtout 15 freopen("in.txt","r",stdin); 16 freopen("out.txt","w",stdout); 17 #endif // txtout 18 while(~scanf("%d%d",&n,&m)){ 19 sx.clear(); 20 sy.clear(); 21 LL tn=n; 22 bool flag=false; 23 int x,y; 24 while(m--){ 25 scanf("%d%d",&x,&y); 26 sx.insert(x); 27 sy.insert(y); 28 LL sum=0; 29 x=sx.size(); 30 y=sy.size(); 31 sum=tn*tn-tn*x-tn*y+1LL*x*y; 32 if(flag) putchar(' '); 33 printf("%I64d",sum); 34 flag=true; 35 } 36 puts(""); 37 } 38 return 0; 39 }
C
题意 给一个串,问选一个最短的子串 ,使得子串中有原串所有类型的字符
比赛是用二分, 枚举起点,二分终点 ,通过前n项和 O56判出是否满足
1 //#define txtout 2 //#define debug 3 #include<bits/stdc++.h> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 typedef long long LL; 7 const double pi=acos(-1.0); 8 const double eps=1e-8; 9 const int inf=0x3f3f3f3f; 10 const int M=1e5+10; 11 int n; 12 char a[M]; 13 int sum[64][M]; 14 int toid(char c){ 15 if(c>='a'&&c<='z') return c-'a'; 16 return c-'A'+26; 17 } 18 void init(){ 19 for(int i=0;i<52;i++){ 20 sum[i][0]=0; 21 } 22 sum[toid(a[0])][0]=1; 23 for(int i=1;i<n;i++){ 24 for(int j=0;j<52;j++){ 25 sum[j][i]=sum[j][i-1]; 26 } 27 sum[toid(a[i])][i]++; 28 } 29 } 30 bool judge(int s,int mid){ 31 for(int i=0;i<52;i++){ 32 if(sum[i][n-1]==0) continue; 33 int total=sum[i][mid]; 34 if(s>0) total-=sum[i][s-1]; 35 if(total<=0) return false; 36 } 37 return true; 38 } 39 int bs(int s){ 40 int L=s,R=n-1,result=-1; 41 while(L<=R){ 42 int mid=(L+R)>>1; 43 if(judge(s,mid)){ 44 result=mid; 45 R=mid-1; 46 } 47 else{ 48 L=mid+1; 49 } 50 } 51 return result; 52 } 53 int solve(){ 54 init(); 55 int answer=n; 56 for(int i=0;i<n;i++){ 57 int last=bs(i); 58 if(last==-1) break; 59 answer=min(answer,last-i+1); 60 } 61 return answer; 62 } 63 int main(){ 64 #ifdef txtout 65 freopen("in.txt","r",stdin); 66 freopen("out.txt","w",stdout); 67 #endif // txtout 68 while(~scanf("%d%s",&n,a)){ 69 printf("%d\n",solve()); 70 } 71 return 0; 72 }
赛后考虑单调队列, 双指针实现,比上述方法快10倍, 开始 起点和终点都在 0, 如果当前种类少于总的种类,则序列一定要变长, 终点往后走一个.
如果当前种类等于总共的种类, 更新答案. 此时说明该起点的最近的终点已经找到, 起点往后走一个. 那么下一个起点必定少了一个字符, 因此种类数只会比之前差,或相等, 因此终点只可能往后走,或是停留原位,不可能往前走,
那么最终起点和终点都是on的往后走, 复杂度on.
1 //#define txtout 2 //#define debug 3 #include<bits/stdc++.h> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 typedef long long LL; 7 const double pi=acos(-1.0); 8 const double eps=1e-8; 9 const int inf=0x3f3f3f3f; 10 const int M=1e5+10; 11 int n; 12 char a[M]; 13 int sum[64]; 14 int toint(char c){ 15 if(c>='a'&&c<='z') return c-'a'; 16 return c-'A'+26; 17 } 18 int solve(){ 19 mt(sum,0); 20 int total=0; 21 for(int i=0;i<n;i++){ 22 int id=toint(a[i]); 23 sum[id]++; 24 if(sum[id]==1) total++; 25 } 26 int result=n; 27 mt(sum,0); 28 int s=0,t=0,nowTotal=1; 29 sum[toint(a[0])]++; 30 while(true){ 31 if(s>=n) break; 32 if(total==nowTotal){ 33 result=min(result,t-s+1); 34 int id=toint(a[s]); 35 sum[id]--; 36 if(sum[id]==0) nowTotal--; 37 if(s+1<=t){ 38 s++; 39 continue; 40 } 41 s=t+1; 42 t=s; 43 continue; 44 } 45 if(t+1>=n) break; 46 t++; 47 int id=toint(a[t]); 48 sum[id]++; 49 if(sum[id]==1) nowTotal++; 50 } 51 return result; 52 } 53 int main(){ 54 #ifdef txtout 55 freopen("in.txt","r",stdin); 56 freopen("out.txt","w",stdout); 57 #endif // txtout 58 while(~scanf("%d%s",&n,a)){ 59 printf("%d\n",solve()); 60 } 61 return 0; 62 }
D
1 //#define txtout 2 //#define debug 3 #include<bits/stdc++.h> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 typedef long long LL; 7 const double pi=acos(-1.0); 8 const double eps=1e-8; 9 const int inf=0x3f3f3f3f; 10 const int M=1e5+10; 11 int n,l,v1,v2,k; 12 13 bool judge(double cut_time,double len,int m){ 14 #ifdef debug 15 printf("cut_time=%.3f len=%.3f m=%d\n",cut_time,len,m); 16 #endif // debug 17 if(m==0) return true; 18 // if(len<eps) return true; 19 if(v2*cut_time<len) return false; 20 double t1=(len-v2*cut_time)/(v1-v2); 21 double t2=cut_time-t1; 22 double left=len-v1*t2; 23 #ifdef debug 24 printf("t1 = %.3f t2 = %.3f left = %.3f\n",t1,t2,left); 25 #endif // debug 26 if(left<eps) return true; 27 double carleft=len-v2*t2; 28 double meettime=(left-carleft)/(v1+v2); 29 left-=v1*meettime; 30 if(left<eps) return true; 31 return judge(t1-meettime,left,m-1); 32 } 33 double solve(){ 34 int m=n/k; 35 if(n%k) m++; 36 double L=0,R=l*1.0/v1; 37 double answer=R; 38 int step=100; 39 while(step--){ 40 double mid=(L+R)*0.5; 41 #ifdef debug 42 printf("judge\n"); 43 #endif // debug 44 if(judge(mid,l,m)){ 45 answer=mid; 46 R=mid; 47 } 48 else{ 49 L=mid; 50 } 51 } 52 return answer; 53 } 54 int main(){ 55 #ifdef txtout 56 freopen("in.txt","r",stdin); 57 freopen("out.txt","w",stdout); 58 #endif // txtout 59 while(~scanf("%d%d%d%d%d",&n,&l,&v1,&v2,&k)){ 60 printf("%.10f\n",solve()); 61 } 62 return 0; 63 }
E 赛后过的,记录一下,其实不难。题意给一个树,其中有2*m个节点是学校。现在要把这些学校两两一组配对,每一对有距离,目标使得m个距离的和最大。
解法:宏观的来看。遍历每一条边,它能经过的次数是左右两边学校个数的小值。 通过dfs处理以u为根的子树的学校个数。 基于贪心的理论,即一条边左右两边都有点的话,会尽可能的让他们配对,那么配对数就是min(left,right)。也就是不考虑具体是哪两个匹配到一起,只要左右两边有点,就会尽可能的去匹配。
1 //#define debug 2 3 #include<bits/stdc++.h> 4 using namespace std; 5 typedef long long LL; 6 const int M=2e5+10; 7 struct E{ 8 int u,v; 9 }e[M]; 10 vector<int> g[M]; 11 int x[M]; 12 int sum[M]; 13 bool is[M]; 14 int n,m; 15 void init(){ 16 for(int i=1;i<=n;i++){ 17 is[i]=false; 18 g[i].clear(); 19 } 20 for(int i=0;i<m;i++){ 21 is[x[i]]=true; 22 } 23 for(int i=0;i<n-1;i++){ 24 g[e[i].u].push_back(e[i].v); 25 g[e[i].v].push_back(e[i].u); 26 } 27 } 28 void dfs_sum(int u,int fa){ 29 sum[u]=is[u]; 30 for(int i=0;i<g[u].size();i++){ 31 int v=g[u][i]; 32 if(v==fa) continue; 33 dfs_sum(v,u); 34 sum[u]+=sum[v]; 35 } 36 } 37 LL answer; 38 void dfs(int u,int fa){ 39 for(int i=0;i<g[u].size();i++){ 40 int v=g[u][i]; 41 if(v==fa) continue; 42 int son=sum[v]; 43 int other=m-sum[v]; 44 if(son<=other){ 45 answer+=son; 46 } 47 else{ 48 answer+=other; 49 } 50 dfs(v,u); 51 } 52 } 53 LL solve(){ 54 init(); 55 dfs_sum(1,-1); 56 57 #ifdef debug 58 for(int i=1;i<=n;i++){ 59 printf("%d ",sum[i]); 60 } 61 puts(""); 62 #endif 63 64 answer=0; 65 dfs(1,-1); 66 return answer; 67 } 68 int main(){ 69 while(~scanf("%d%d",&n,&m)){ 70 m<<=1; 71 for(int i=0;i<m;i++){ 72 scanf("%d",&x[i]); 73 } 74 for(int i=0;i<n-1;i++){ 75 scanf("%d%d",&e[i].u,&e[i].v); 76 } 77 printf("%I64d\n",solve()); 78 } 79 return 0; 80 }
F 赛后研究好几天也没过,后看了别人的思想 ,实现了好几天,终于过了. 题意给一个无向图, 删去小于等于2条边,使得st两点不连通 ,删去边 有花费 ,问总花费最小的方案.
解法: 本来不通 0. 随便找一条 S 到T 路径, 必须删去路径上的一条边, 枚举 删去哪条 ,因为路径的边数只有n-1条. 删去边后, 判断, 如果不通了 , 那么删这条边是一种方案, 如果还通, 做tarjan缩点,
当ST在一个连通分量内, 因为我们只剩一条可以删, 因此肯定无解 , 不在一个连通分量时 , 我们还是随便找一条 S到T的路径, 判断 路径上是否有桥, 有则可以通过删他达到目的.
枚举第一条边n , tarjan m, n*m的复杂度, 可能有更快的方法?
1 //#define txtout 2 //#define debug 3 #include<bits/stdc++.h> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 typedef long long LL; 7 const double pi=acos(-1.0); 8 const double eps=1e-8; 9 const int inf=0x3f3f3f3f; 10 const int M=1e5+10; 11 int n,m,s,t; 12 struct E { 13 int u,v,w; 14 } e[M]; 15 struct G { 16 struct E { 17 int v,w,id,next; 18 } e[M]; 19 int le,head[M]; 20 void init(int n) { 21 le=0; 22 for(int i=0; i<=n; i++) head[i]=-1; 23 } 24 void add(int u,int v,int w,int id) { 25 e[le].v=v; 26 e[le].w=w; 27 e[le].id=id; 28 e[le].next=head[u]; 29 head[u]=le++; 30 } 31 } g; 32 struct A { 33 int sum; 34 vector<int> id; 35 void init() { 36 sum=-1; 37 id.clear(); 38 } 39 void update(int tsum,int id1,int id2) { 40 if(sum==-1||tsum<sum) { 41 sum=tsum; 42 id.clear(); 43 if(~id1) id.push_back(id1); 44 if(~id2) id.push_back(id2); 45 } 46 } 47 } answer; 48 class Tarjan_U { ///����ͼ��ͨ�������� O(V+E) 49 typedef int typec; ///��Ȩ������ 50 static const int ME=1e5+10; ///�ߵĸ��� 51 static const int MV=1e3+10; ///��ĸ��� 52 int n,Bcnt,Index,num[MV],dfn[MV],low[MV],belong[MV]; 53 stack<int> s; 54 void addqiao(int u,int v,typec w) { 55 now.u=u; 56 now.v=v; 57 now.w=w; 58 qiao.push_back(now); 59 } 60 void tarjan(int u) { 61 s.push(u); 62 dfn[u]=low[u]=++Index; 63 int v; 64 for(int i=g.head[u]; ~i; i=g.e[i].next) { 65 if(g.e[i].vis) continue; 66 g.e[i].vis=g.e[i^1].vis=true; 67 v=g.e[i].v; 68 if (!dfn[v]) { 69 tarjan(v); 70 low[u]=min(low[u],low[v]); 71 if(dfn[u]<low[v]){ 72 addqiao(u,v,g.e[i].w); 73 isbridge[g.e[i].id]=true; 74 } 75 continue; 76 } 77 low[u]=min(low[u],dfn[v]); 78 } 79 if(dfn[u]!=low[u]) return ; 80 Bcnt++; 81 do { 82 v=s.top(); 83 s.pop(); 84 belong[v]=Bcnt; 85 num[Bcnt]++; 86 } while(v!=u); 87 } 88 struct G { 89 struct E { 90 int id; 91 int v,next; 92 bool vis; 93 typec w; 94 } e[ME]; 95 int le,head[MV]; 96 void init(int n) { 97 le=0; 98 for(int i=0; i<=n; i++) head[i]=-1; 99 } 100 void add(int u,int v,typec w,int id) { 101 e[le].vis=false; 102 e[le].v=v; 103 e[le].w=w; 104 e[le].id=id; 105 e[le].next=head[u]; 106 head[u]=le++; 107 } 108 } g; 109 struct Q { 110 int u,v; 111 typec w; 112 } now; 113 vector<Q> qiao; 114 bool isbridge[ME]; 115 public: 116 bool is_bridge(int id){ 117 return isbridge[id]; 118 } 119 void init(int tn) { ///������������±� 1 ��ʼ 120 n=tn; 121 g.init(n); 122 } 123 void add(int u,int v,typec w,int id) { 124 g.add(u,v,w,id); 125 g.add(v,u,w,id); 126 } 127 void solve() { 128 Index=Bcnt=0; 129 for(int i=1; i<=n; i++) { 130 num[i]=dfn[i]=low[i]=0; 131 } 132 for(int i=0;i<m;i++){ 133 134 isbridge[i]=false; 135 } 136 qiao.clear(); 137 while(!s.empty()) s.pop(); 138 for(int i=1; i<=n; i++) { 139 if(!dfn[i]) { 140 tarjan(i); 141 } 142 } 143 } 144 int getbcnt() { ///��ͨ�����ĸ��� 145 return Bcnt; 146 } 147 int getbelong(int id) { ///�����ĸ������������±� 1 ��ʼ 148 return belong[id]; 149 } 150 int getnum(int id) { ///ij�������ĵ�ĸ��� 151 return num[id]; 152 } 153 } tarjan; 154 bool tabu[M]; 155 int pre[M]; 156 vector<int> EID,EID2; 157 bool dfs(int u,int deleteID) { 158 tabu[u]=true; 159 if(u==t) return true; 160 for(int i=g.head[u]; ~i; i=g.e[i].next) { 161 int id=g.e[i].id; 162 if(id==deleteID) continue; 163 int v=g.e[i].v; 164 if(tabu[v]) continue; 165 pre[v]=u; 166 bool flag=dfs(v,deleteID); 167 if(flag) return true; 168 } 169 return false; 170 } 171 bool check_c(int deleteID) { 172 for(int i=1; i<=n; i++) { 173 tabu[i]=false; 174 } 175 return dfs(s,deleteID); 176 } 177 void get_edge(vector<int> &a,int deleteID) { 178 a.clear(); 179 int u=t; 180 while(u!=s) { 181 for(int i=g.head[u]; ~i; i=g.e[i].next) { 182 int id=g.e[i].id; 183 if(id==deleteID) continue; 184 int v=g.e[i].v; 185 if(v!=pre[u]) continue; 186 a.push_back(g.e[i].id); 187 u=v; 188 break; 189 } 190 } 191 } 192 void Delete(int deleteID) { 193 bool flag=check_c(deleteID); 194 if(!flag) { 195 answer.update(e[deleteID].w,deleteID,-1); 196 return ; 197 } 198 tarjan.init(n); 199 for(int i=0;i<m;i++){ 200 if(i==deleteID) continue; 201 tarjan.add(e[i].u,e[i].v,e[i].w,i); 202 } 203 tarjan.solve(); 204 if(tarjan.getbelong(s)==tarjan.getbelong(t)) return ; 205 get_edge(EID2,deleteID); 206 for(int i=0;i<EID2.size();i++){ 207 int id=EID2[i]; 208 #ifdef debug 209 printf("id2=%d\n",id); 210 #endif // debug 211 if(!tarjan.is_bridge(id)) continue; 212 answer.update(e[deleteID].w+e[id].w,deleteID,id); 213 } 214 } 215 void solve() { 216 answer.init(); 217 g.init(n); 218 for(int i=0; i<m; i++) { 219 g.add(e[i].u,e[i].v,e[i].w,i); 220 g.add(e[i].v,e[i].u,e[i].w,i); 221 } 222 bool flag=check_c(-1); 223 if(!flag) { 224 answer.update(0,-1,-1); 225 return ; 226 } 227 get_edge(EID,-1); 228 for(int i=0; i<EID.size(); i++) { 229 #ifdef debug 230 printf("id=%d\n",EID[i]); 231 #endif // debug 232 Delete(EID[i]); 233 } 234 } 235 int main() { 236 #ifdef txtout 237 freopen("in.txt","r",stdin); 238 freopen("out.txt","w",stdout); 239 #endif // txtout 240 while(~scanf("%d%d%d%d",&n,&m,&s,&t)) { 241 for(int i=0; i<m; i++) { 242 scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); 243 } 244 solve(); 245 int sum=answer.sum; 246 printf("%d\n",sum); 247 if(sum==-1) continue; 248 printf("%d\n",answer.id.size()); 249 for(int i=0; i<answer.id.size(); i++) { 250 printf("%d%c",answer.id[i]+1,i==answer.id.size()-1?'\n':' '); 251 } 252 } 253 return 0; 254 }
end