LouZhang

导航

CUG2012年暑期ACM训练赛(单人赛)

A题是一个模拟或者说是搜索吧

就跟倒可乐的问题差不多

原题是ZOJ1005题

View Code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
 
char ans[101000][10];
int main(){
    int tcase;
    scanf("%d", &tcase);
    //int flag = 0;
    while(tcase --){
        int count = 0;
        int x, y, z;
        scanf("%d%d%d", &x, &y, &z);
        char a, b;
        if(x < y){
            a = '1';
            b = '2';
        }else{
            a = '2';
            b = '1';
            swap(x, y);
        }
        //int xx = 0, yy = 0;
        sprintf(ans[count++], "F(%c)\n", b);
        sprintf(ans[count++], "P(%c,%c)\n", b, a);
        int now = y - x;
        while(now != z){
           // printf("%d %d %d %d\n", count, x , y,z );
 
            if(now > x){
                sprintf(ans[count++], "E(%c)\n", a);
                sprintf(ans[count++], "P(%c,%c)\n", b, a);
                now -= x;
            }else{
                sprintf(ans[count++], "E(%c)\n", a);
                sprintf(ans[count++], "P(%c,%c)\n", b, a);
                sprintf(ans[count++], "F(%c)\n", b);
                sprintf(ans[count++], "P(%c,%c)\n", b, a);
                now = (now + y - x) % y;
            }
            if(count > 2500)break;
        }
        if(count > 2500){
            puts("Impossible!");
 
        }else{
        printf("%d\n", count);
        for(int i = 0; i < count ; i ++)
        printf("%s", ans[i]);}
        if(tcase != 0)
        puts("");
    }
    return 0;
}

B题是一个凸包问题,我完全不会= =、

学弟们都会做。。。。我弱爆了啊

这题用的是ZY给我的模板,然后直接套的,最后加上一个圆的周长就行了

View Code
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
 
using namespace std;
 
struct point{
    double x, y;
}p[1010], stack[1010];
int n, top;
double mul(point a, point b, point c){
    return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
}
double dis(point a, point b){
    return sqrt((a.x -b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
int cmp(const void *a, const void *b){
    point c = *(point *)a;
    point d = *(point *)b;
    double k = mul(p[0], c, d);
    if(k < 0 || (!k && dis(c, p[0]) > dis(d, p[0])) )
      return 1;
    return -1;
}
void convex(){
    for(int i = 1; i < n; i ++){
        point tmp;
        if(p[i].y < p[0].y || (p[i].y == p[0].y && p[i].x < p[0].x)){
            swap(p[i], p[0]);
        }
    }
    qsort(p + 1, n - 1, sizeof(p[0]), cmp);
    stack[0] = p[0];
    stack[1] = p[1];
    top = 1;
    for(int i = 2; i < n; i ++){
        while(top >= 1 && mul(stack[top - 1], stack[top], p[i]) <= 0)
          top --;
        top ++;
        stack[top] = p[i];
    }
}
 
 
int main(){
    double r;
    while(~scanf("%d%lf", &n, &r)){
        for(int i = 0; i < n; i ++){
            scanf("%lf%lf", &p[i].x, &p[i].y);
        }
        convex();
        double ans = 0;
        for(int i = 0; i < top ;i ++){
            ans += dis(stack[i], stack[i+1]);
        }
        ans += dis(stack[top], stack[0]);
        ans += 2 * acos(-1.0) * r;
        printf("%.0f\n", ans);
    }
    return 0;
}

C题就不说了,暴力能过,数据弱啊。。。。

View Code
#include<cstdio>
 
int a[10000 + 10];
int main(){
    int tcase;
    scanf("%d", &tcase);
    while(tcase --){
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; i ++)
          scanf("%d", a + i);
        int flag = 0;
        for(int i = 2; i <= n - 1; i ++){
            for(int j = 1; j < i; j ++){
                for(int k = i + 1; k <= n; k ++){
                    if(a[j] + a[k] == 2 * a[i]){
                        flag = 1;
                        break;
                    }
                }
                if(flag)
                  break;
            }
            if(flag)
              break;
        }
        if(flag)
          puts("Yes");
        else
          puts("No");
    }
    return 0;
}

D题也不说了,不会做,搞不懂题,这么多人WA了,没有人过、。

 

E题纯数据结构+模拟啊,不想敲了,写起来太麻烦了

 

F题我开始用n^2的DP 直接 TLE了,后来ZY说用NlogN,然后就直接过了。。

View Code
#include<cstdio>
#include<cstring>
#include<algorithm>
 
using namespace std;
 
struct node{
    int x, y;
    friend bool operator < (const node &a, const node &b){
        return a.x < b.x;
    }
}p[10010];
int dp[10010];
int a[10010];
int binary_search(int c[],int len,int v)
{
    int left=0,right=len-1,mid=left+(right-left)/2;
    while(left<=right){
        if(v>c[mid])   left=mid+1;
        else if(v<c[mid])   right=mid-1;
        else return mid;
        mid=left+(right-left)/2;
    }
    return left;
}
int main(){
    int tcase;
    scanf("%d", &tcase);
    while(tcase --){
        int n;
        scanf("%d", &n);
        for(int i = 0; i < n; i ++){
            scanf("%d%d", &p[i].x, &p[i].y);
            dp[i] = 1;
        }
        sort(p, p + n);
        /*
        for(int i = 1; i < n; i ++){
            for(int j = 0; j < i; j ++){
                if(p[i].y> p[j].y)
                  if(dp[i] < dp[j] + 1)
                    dp[i] = dp[j] + 1;
            }
        }
        */
        int top = 0;
        a[top++] = p[0].y;
        for(int i = 1; i < n; i ++){
            if(a[top - 1] < p[i].y)
              a[top++] = p[i].y;else{
                  int tmp = binary_search(a, top, p[i].y);
                  a[tmp] = p[i].y;
              }
        }
 
        int ans = 0;
        /*
        for(int i = 0; i < n; i ++)
          if(ans < dp[i])
            ans = dp[i];
            */
        printf("%d\n", top);
    }
    return 0;
}

G题不知道110是怎么出来的

 

H题还是有那么点意思的

我的思路是,对每一个点进行DFS

DFS的过程中,每走到一个C就把该点变成*

这样就能计数了

View Code
#include<cstdio>
#include<cstring>
 
int vis[10000 + 10];
char map[110][110];
int n,m;
int dir[8][2]={
    1,1,1,0,1,-1,-1,1,-1,0,-1,-1,0,1,0,-1
};
void dfs(int x, int y){
    map[x][y] = '*';
    for(int i = 0; i < 8; i ++){
        int xx = x + dir[i][0];
        int yy = y + dir[i][1];
        if(map[xx][yy] == 'C'){
            dfs(xx, yy);
        }
    }
}
int main(){
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; i ++)
      scanf("%s", map[i]);
    memset(vis, -1, sizeof(vis));
    int count = 0;
    for(int i = 0; i < n; i ++){
        for(int j = 0; j < m ; j ++)
          if(map[i][j] == 'C'){
              dfs(i, j);
              count ++;
          }
    }
    printf("%d\n", count);
    return 0;
}

I题用java做的

当时没有编译器

直接vim编写的,那当然错误一大堆

后来还是装了eclipse了

View Code
import java.math.BigInteger;
import java.util.Scanner;
  
public class Main{
    public static void main(String args[]){
        Scanner cin = new Scanner(System.in);
        int t;
        t = cin.nextInt();
        while(t-- != 0){
            int n;
            n = cin.nextInt();
            n --;
            BigInteger a = cin.nextBigInteger();
            while(n-- != 0){
                BigInteger b = cin.nextBigInteger();
                //System.out.println(b);
                //a.subtract(b);
                //System.out.println(a.subtract(b));
                a = a.subtract(b);
            }
            System.out.println(a);
        }
    }
}

J题不会做

 

做了6题,感觉最遗憾的当是图论那题和最后一题了,不会啊。。继续加油学吧

 

--------------------------------更新----------------------------------------------

本来不想做的,数论不会啊。。。。但怕第一的位子没了。。还是做了

不过做是做了,也是看着解题报告做的= =原题

http://poj.org/problem?id=2154 就是这题了,一看出处吓死了,楼教主的原题啊。。

一开始的时候以为是polya定理来做,然后就直接套模板敲了

不过后来发现不一样啊,并不翻转

然后就找特殊情况加着求了,然后果断TLE

10亿的数据啊。。。

后来问了dream神,他给我讲了一通

然后他告诉我是哪题了,再去看解题报告 。。。

很遗憾。。。没有完全看懂。。。大概的理解了。。

解法也在下面了。。

View Code
#include<iostream>
#include<math.h>
#include<cstdio>
#include<cstring>
using namespace std;

/*
置换只有旋转一种方式,那么共有n个置换
基本知识:环的个数为gcd(n , i) , 长度L=n / gcd(n , i)   其中 i 为转的位子数
普通求法: ∑n^( gcd(n,i) )  0<=i<n  复杂度过高
优化:枚举环的长度L
枚举优化: L可以从1取到sqrt(n) ,因为L|n , n/L | n
对于每个L,我们再看有几个i满足条件
n/L = gcd(n , i)
那么令 a=n/L = gcd(n , i) , 再设i = at
那么当且仅当gcd(L,t)=1时候,才有gcd(n,i) = a
显然满足条件的i的个数就是t的个数也就是phi(L)
那么最后统计一下就是 ∑(phi(L) * N^(L-1) ) % p  (L即枚举值)
*/

const int maxn = 50000;
bool IsNotPrime[maxn]; // 判断是否为素数.
int PrimeList[maxn]; // 素数列表.
int PrimeNum;

void Prime_Linear(void)
{ // 速度比朴素筛法快2倍以上,该筛法进行稍微修改即可用于求欧拉函数Phi[].
    int i, j;
    memset(IsNotPrime, 0, sizeof(IsNotPrime)); // 初始赋值所有数都是素数.
    IsNotPrime[1] = 1; IsNotPrime[0] = 1; // 0和1不是素数.
    PrimeList[0]=2;
    for (i = 4; i < maxn; i += 2) IsNotPrime[i] = 1; // 除2以外的所有偶数都不是素数.
    PrimeNum = 1;
    for (i = 3; i < maxn; i += 2)
    {
        if (!IsNotPrime[i])
        { // 如果是素数则加入素数列表.
            PrimeList[PrimeNum++] = i;
        }
        // 注意:这里与朴素筛法不同,即使合数也要进行筛.
        // 因为这里素数只筛它的素数倍,那么有些合数就可能没被筛掉.
        // 而这些合数就需要合数来晒,而且只要筛到它的最小质因子倍即可(想想为什么?).
        for (j = 0; j < PrimeNum && i * PrimeList[j] < maxn; j++)
        {
            IsNotPrime[i * PrimeList[j]] = 1;
            if (i % PrimeList[j] == 0)
            { // 说明PrimeList[j]是i的最小质因子,即i * PrimeList[j]的最小质因子,则跳出.
                break;
            }
        }
    }
}

int modular_exponent(int a, int b, int n){
    int ret = 1;
    a %= n;
    for( ; b; b >>= 1, a = (int)( (long long )a) * a % n ){
        if(b & 1)
          ret = (int)((long long )ret) * a % n;
    }
    return ret;
}
int euler(int x){
    int res = x;
    for(int i = 0; i < PrimeNum && PrimeList[i] * PrimeList[i] <= x; i ++){
        if(x % PrimeList[i] == 0){
            res = res / PrimeList[i] * (PrimeList[i] -1);
            while(x % PrimeList[i] == 0){
                x /= PrimeList[i];
            }
        }
    }
    if(x > 1)
        res = res / x * ( x - 1);
    return res;
}
int main(){
    int tcase;
    scanf("%d", &tcase);
    Prime_Linear();
    while(tcase --){
        int n, p;
        scanf("%d%d", &n, &p);
        int ans = 0;
        int i;
        for( i = 1; i * i < n; i ++)
        if(n%i == 0){
            ans = (ans + euler(i) % p * modular_exponent(n, n/i-1, p)
                   + euler(n/i) %p * modular_exponent(n, i-1, p)) % p;
        }
        if (i * i == n)
        ans = (ans + euler(i) * modular_exponent(n, i-1, p)) % p;
        printf("%d\n", ans);
    }
    return 0;
}

D题继续不懂,他说我没有看清题 ?听说是CF的原题。。。

E题继续打死不写

G题是网络流啊,110也知道是怎么出来的了

因为题目中已经说清楚了是无向边

不过数据中竟然给了2 3 和3 2 这种情况。。。。。这。。。。太坑了啊。。

因为边可能重边之类的

所以要用floyd来计算最短路了,即所有点之间的最短值了。。。

然后就是用网络流了。。。

不会啊,还不理解。。。

还是巩固下吧

 -----------------------继续更新--------------------------

C题,原来没看清题啊。。跪 

出现的数一定是从1-n并且全部填完的。。。这样的话,就跟逆序数那题差不多啊。。

View Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;


int a[10000+10];
int flag[10000+10];
int main(){
    int tcase;
    scanf("%d", &tcase);
    while(tcase --){
        int n;
        memset(flag, 0, sizeof flag);
        scanf("%d", &n);
        for(int i = 0; i < n; i ++) scanf("%d", a + i);
        int f = 0;
        /*
        for(int i = 0; i < n; i ++){
            flag[ a[i] ] = 1;
            for(int j = a[i] + 1; j < n -a[i]; j ++){
                if(flag[ a[i] - j] + flag[ a[i] + j] == 1){
                    f = 1;
                    break;
                }
            }
            if(f)
              break;
        }
        */
        //JZ同学说只要大于5一定是YES了Orz
        if(n >= 5){
            puts("Yes");
            continue;
        }
        for(int i = 0; i < n; i ++){
            for(int j = 0; j < i; j ++){
                for(int k = i + 1; k < n; k ++){
                    if(a[i] * 2 == a[j] + a[k]){
                        f = 1;
                        break;
                    }
                }
            }
        }
        if(f)
          puts("Yes");
        else
          puts("No");
    }
    return 0;
}

D题,单调队列

见这个

http://www.cnblogs.com/louzhang/archive/2012/08/01/2617837.html

 这个就更新到这吧,博客也写的挫。。。写的也累死了

posted on 2012-07-28 23:26  louzhang_swk  阅读(388)  评论(0编辑  收藏  举报