zoukankan      html  css  js  c++  java
  • CSU-ACM暑假集训基础组七夕专场

    •Problem A Codeforces 20C       最短路(dij,spfa)
    •题意:给出一张n个点m条边的无向图 (2 ≤ n ≤ 105, 0 ≤ m ≤ 105),输出从1到n的任意一条最短路径。
    •解法:dijkstra或者spfa,用pre数组记录到达每个点最短距离的前驱结点。
    •注意:路径的长度范围是 1 ≤ wi ≤ 106,从1到n的最短路径长度可能超出int范围。
    •没有路径从1到达n时要输出-1
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <queue>
     4 #include <algorithm>
     5 using namespace std;
     6 typedef long long LL;
     7 typedef pair<LL,int> pii;
     8 const int maxn = 100010;
     9 const int maxm = 200010;
    10 int v[maxm],next[maxm],w[maxm];
    11 int first[maxn],pre[maxn],res[maxn],e;
    12 LL d[maxn];
    13 
    14 void init(){
    15     e = 0;
    16     memset(first,-1,sizeof(first));
    17 }
    18 
    19 void add_edge(int a,int b,int c){
    20     v[e] = b;next[e] = first[a];w[e] = c;first[a] = e++;
    21 }
    22 
    23 void dijkstra(int src){
    24     priority_queue <pii,vector<pii>,greater<pii> > q;
    25     memset(d,-1,sizeof(d));
    26     d[src] = 0;
    27     q.push(make_pair(0,src));
    28     while(!q.empty()){
    29         while(!q.empty() && q.top().first > d[q.top().second])  q.pop();
    30         if(q.empty())   break;
    31         int u = q.top().second;
    32         q.pop();
    33         for(int i = first[u];i != -1;i = next[i]){
    34             if(d[v[i]] > d[u]+w[i] || d[v[i]] == -1){
    35                 d[v[i]] = d[u]+w[i];
    36                 q.push(make_pair(d[v[i]],v[i]));
    37                 pre[v[i]] = u;
    38             }
    39         }
    40     }
    41 }
    42 
    43 int main(){
    44     init();
    45     int n,m,a,b,c;
    46     scanf("%d%d",&n,&m);
    47     for(int i = 0;i < m;i++){
    48         scanf("%d%d%d",&a,&b,&c);
    49         add_edge(a,b,c);
    50         add_edge(b,a,c);
    51     }
    52     dijkstra(1);
    53     int now = n,cnt = 0;
    54     if(d[n] == -1){
    55         printf("-1");
    56         return 0;
    57     }
    58     while(now != 1){
    59         res[cnt++] = now;
    60         now = pre[now];
    61     }
    62     res[cnt++] = 1;
    63     for(int i = cnt-1;i >= 0;i--)  printf("%d ",res[i]);
    64     return 0;
    65 }
    View Code
    •Problem B Codeforces 295B     最短路(floyd)
    •题意:对于一个带权有向图,每次删除一个点,要求计算出删除该点前当前图的所有点间的最短距离之和。
    •首先,想知道任意两点间最短距离之和应该使用什么算法?
    •毫无疑问 Floyd!
    •对于删除顺序,我们可以怎么处理?
    •可以反过来做。这样就相当于每次添加一个点到图中,然后询问当前图的所有点间最短距离之和。
    •对于每次新增加的点v,我们用v对整张图进行松弛操作:d[s][t] = min(d[s][t],d[s][v]+d[v][t])
    •对于统计操作,可以暴力枚举。
    •整个复杂度为O(n^3)
    •注意:本题数据范围可能超过int
     1 #include <cstdio>
     2 #include <cstring>
     3 #define maxn 510
     4 typedef long long LL;
     5 LL d[maxn][maxn];
     6 int seq[maxn];
     7 LL ans[maxn];
     8 
     9 inline LL min(LL a,LL b){
    10     return a < b ? a : b;
    11 }
    12 
    13 void update(int s,int n){
    14     for(int i = 1;i <= n;i++)
    15         for(int j = 1;j <= n;j++)
    16             d[i][j] = min(d[i][s] + d[s][j],d[i][j]);
    17 }
    18 
    19 LL query(int s,int n){
    20     LL sum = 0;
    21     for(int i = n,u = seq[i];i >= s;u = seq[--i])
    22         for(int j = n,v = seq[j];j >= s;v = seq[--j])
    23             sum += d[u][v];
    24     return sum;
    25 }
    26 
    27 int main()
    28 {
    29     int n;
    30     while(scanf("%d",&n) != EOF){
    31         for(int i = 1;i <= n;i++)
    32             for(int j = 1;j <= n;j++)
    33                 scanf("%I64d",&d[i][j]);
    34         for(int i = 1;i <= n;i++)
    35             scanf("%d",&seq[i]);
    36         for(int i = n;i >= 1;i--){
    37             update(seq[i],n);
    38             ans[i] = query(i,n);
    39         }
    40         for(int i = 1;i <= n;i++)
    41             printf("%I64d ",ans[i]);
    42         printf("
    ");
    43     }
    44     return 0;
    45 }
    View Code
    •Problem C SPOJ MULTQ3           线段树
    •题意:有一个长为N(N<=10^5)的数组,初始时数组每个元素的值都为0,接下来有Q(Q<=10^5)次操作,每次操作有2中类型:
    •0 A B 将[A,B]区间内的所有数字+1
    •1 A B 输出[A,B]区间内所有能够被3整除的数组元素的个数
    •考察内容:
    •线段树的基本应用
    •区间维护
    •Lazy标记的使用
    •每次修改时,如果某个节点表示的区间[x,y]被加了1,那么我们要对这个区间的3个sum属性进行修改,同时在这个区间打上lazy标记,表示这个区间已经被修改了。
    •当需要访问这个节点下面的节点的时候,一定会先经过这个点,这时候下传lazy标记,来保证子节点的信息是正确的。
     1 #include <cstdio>
     2 const int maxn = 100010;
     3 int sum[maxn<<2][3],add[maxn<<2];
     4 
     5 void pushup(int cur){
     6     int ls = cur<<1,rs = cur<<1|1;
     7     sum[cur][0] = sum[ls][0]+sum[rs][0];
     8     sum[cur][1] = sum[ls][1]+sum[rs][1];
     9     sum[cur][2] = sum[ls][2]+sum[rs][2];
    10 }
    11 
    12 void pushdown(int cur){
    13     int ls = cur<<1,rs = cur<<1|1,tmp;
    14     if(add[cur] != 0){
    15         add[ls] = (add[ls]+add[cur])%3;
    16         add[rs] = (add[rs]+add[cur])%3;
    17         if(add[cur] == 1){
    18             tmp = sum[ls][2];
    19             sum[ls][2] = sum[ls][1];
    20             sum[ls][1] = sum[ls][0];
    21             sum[ls][0] = tmp;
    22         }else if(add[cur] == 2){
    23             tmp = sum[ls][0];
    24             sum[ls][0] = sum[ls][1];
    25             sum[ls][1] = sum[ls][2];
    26             sum[ls][2] = tmp;
    27         }
    28         if(add[cur] == 1){
    29             tmp = sum[rs][2];
    30             sum[rs][2] = sum[rs][1];
    31             sum[rs][1] = sum[rs][0];
    32             sum[rs][0] = tmp;
    33         }else if(add[cur] == 2){
    34             tmp = sum[rs][0];
    35             sum[rs][0] = sum[rs][1];
    36             sum[rs][1] = sum[rs][2];
    37             sum[rs][2] = tmp;
    38         }
    39         add[cur] = 0;
    40     }
    41 }
    42 
    43 void bulid(int cur,int x,int y){
    44     int mid = (x+y)>>1,ls = cur<<1,rs = cur<<1|1;
    45     if(x == y){
    46         sum[cur][0] = 1;
    47         return;
    48     }
    49     bulid(ls,x,mid);
    50     bulid(rs,mid+1,y);
    51     pushup(cur);
    52 }
    53 
    54 void update(int cur,int x,int y,int s,int t){
    55     int mid = (x+y)>>1,ls = cur<<1,rs = cur<<1|1;
    56     if(x >= s && y <= t){
    57         int tmp = sum[cur][2];
    58         sum[cur][2] = sum[cur][1];
    59         sum[cur][1] = sum[cur][0];
    60         sum[cur][0] = tmp;
    61         add[cur] = (add[cur]+1)%3;
    62         return;
    63     }
    64     pushdown(cur);
    65     if(mid >= s)    update(ls,x,mid,s,t);
    66     if(mid+1 <= t)  update(rs,mid+1,y,s,t);
    67     pushup(cur);
    68 }
    69 
    70 void query(int cur,int x,int y,int s,int t,int &ans){
    71     int mid = (x+y)>>1,ls = cur<<1,rs = cur<<1|1;
    72     if(x >= s && y <= t){
    73         ans += sum[cur][0];
    74         return;
    75     }
    76     pushdown(cur);
    77     if(mid >= s)    query(ls,x,mid,s,t,ans);
    78     if(mid+1 <= t)  query(rs,mid+1,y,s,t,ans);
    79 }
    80 
    81 int main(){
    82     int n,q,op,a,b;
    83     scanf("%d%d",&n,&q);
    84     bulid(1,0,n-1);
    85     while(q--){
    86         scanf("%d%d%d",&op,&a,&b);
    87         if(op == 0) update(1,0,n-1,a,b);
    88         else{
    89             int ans = 0;
    90             query(1,0,n-1,a,b,ans);
    91             printf("%d
    ",ans);
    92         }
    93     }
    94     return 0;
    95 }
    View Code
    •Problem D Codeforces 4C          Map
    •题意:输入一个单词,查询字典内是否含有这个单词,如果没有,输出“OK”,将这个新单词插入字典中。如果有,输出做这个单词,后面紧接着输出这个单词出现的次数。
    •考察内容:Map的使用
     1 #include <iostream>
     2 #include <string>
     3 #include <map>
     4 using namespace std;
     5 map<string,int> m;
     6 
     7 int main(){
     8     int n,a;
     9     string str;
    10     cin>>n;
    11     while(n--){
    12         cin>>str;
    13         a = m[str]++;
    14         if(a)   cout<<str<<a<<endl;
    15         else    cout<<"OK"<<endl;
    16     }
    17     return 0;
    18 }
    View Code
    •Problem E SPOJ ROCK                 DP
    •题意:有一块n个单位长的糖,有的地方是甜的(1),有的地方是酸的(0)。你可以将整块糖任意切成若干段。小盆友们只会买走甜的长度比酸的长度多的那段糖。问经过切割后,最多可以卖掉多少单位长度的糖。
    •考察知识:DP
    •dp(i)表示将前i段糖进行切割后最多能卖掉的数量
    •状态转移方程:
    •考虑在第j段之前切一刀
    •dp(i)=max{ dp(i) , dp(j-1) +i–j+1}
    •( 1 <= j <= i 且在[j,i]区间内甜的比酸的多)
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 const int maxn = 205;
     6 char str[maxn];
     7 int dp[maxn],sum[maxn][2];
     8 
     9 int main(){
    10     int T,len;
    11     scanf("%d",&T);
    12     while(T--){
    13         scanf("%d %s",&len,str+1);
    14         sum[0][0] = sum[0][1] = 0;
    15         for(int i = 1;i <= len;i++){
    16             sum[i][0] = sum[i-1][0];
    17             sum[i][1] = sum[i-1][1];
    18             sum[i][str[i]-'0']++;
    19         }
    20         dp[0] = 0;
    21         for(int i = 1;i <= len;i++){
    22             dp[i] = dp[i-1];
    23             for(int j = 1;j <= i;j++){
    24                 int sum0 = sum[i][0]-sum[j-1][0];
    25                 int sum1 = sum[i][1]-sum[j-1][1];
    26                 if(sum1 <= sum0)    continue;
    27                 dp[i] = max(dp[i],dp[j-1]+i-j+1);
    28             }
    29         }
    30         printf("%d
    ",dp[len]);
    31     }
    32     return 0;
    33 }
    View Code
    •Problem F SPOJ NITK06              模拟
    •题意:给出一个长为n的数列ai(1<=i<=n),每个元素都非负。每次你可以选择一个下标x(1<=x<=n-1),将ax和ax+1同时减1。问经过若干次操作,能否将原数列变成一个元素全部为0的序列。
    •模拟即可。
    •从数列第一个元素开始,用它剩下的值减去下一个元素的值
    •最后如果所有元素都能变为0,则满足条件。
     1 #include <cstdio>
     2 int a[10010];
     3 
     4 int main(){
     5     int T,n;
     6     scanf("%d",&T);
     7     while(T--){
     8         scanf("%d",&n);
     9         for(int i = 0;i < n;i++)    scanf("%d",&a[i]);
    10         if(n == 1){
    11             if(a[0] == 0)   printf("YES
    ");
    12             else            printf("NO
    ");
    13             continue;
    14         }
    15         bool flag = 0;
    16         for(int i = 0;i < n-1;i++){
    17             if(a[i] < 0){
    18                 flag = 1;
    19                 break;
    20             }
    21             a[i+1] -= a[i];
    22         }
    23         if(a[n-1] != 0) flag = 1;
    24         if(flag)    printf("NO
    ");
    25         else        printf("YES
    ");
    26     }
    27     return 0;
    28 }
    View Code
  • 相关阅读:
    最大流问题
    字符串的回文与镜像
    字符串的回文与镜像
    Aho
    linux环境变量
    【Centos7】安装memcached
    linux命令后台执行
    ubuntu常见错误--Could not get lock /var/lib/dpkg/lock解决
    ubuntu server解决不能访问外网问题
    【Ubuntu 16】安装net-snmp
  • 原文地址:https://www.cnblogs.com/zhexipinnong/p/3885411.html
Copyright © 2011-2022 走看看