20130712周赛CF147div2

血虐啊大哭

今天的CF就只有第一题写的还行,虐惨了,被。。。。

A. Free Cash

题意:给出顾客的来访时间,让你计算需要配备多少cashes,so that they can serve all visitors.

刚开始用s[24][60]来累加,后面判断答案的时候选错了。后来又改了一维的数组,按求max值的方法过了,刚刚又改了一下二维数组的代码,A了

先上二维的代码:

#include <iostream>
#include <cstdio>
#include <string>
#include <string.h>
#include <map>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
using namespace std;
int min(int a, int b)
{
    if(a<=b)
        return a;
    return b;
}
int max(int a, int b)
{
    if(a>=b)
        return a;
    return b;
}
double min(double a, double b)
{
    if(a<=b)
        return a;
    return b;
}
double max(double a, double b)
{
    if(a>=b)
        return a;
    return b;
}

int main()
{
    int n;
    scanf("%d", &n);
    int h, m;
    int s[24][60];
    int max = 0;
    memset(s, 0, sizeof(s));
    for(int i = 0; i < n; ++i)
    {
        scanf("%d%d", &h, &m);
        s[h][m]++;
        if(max < s[h][m])
            max = s[h][m];
    }
    printf("%d\n", max);
    return 0;
}
用一维的写的就是这样了,其实原理都是一样的,也是求max的

#include <iostream>
#include <cstdio>
#include <string>
#include <string.h>
#include <map>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
using namespace std;
int min(int a, int b)
{
    if(a<=b)
        return a;
    return b;
}
int max(int a, int b)
{
    if(a>=b)
        return a;
    return b;
}
double min(double a, double b)
{
    if(a<=b)
        return a;
    return b;
}
double max(double a, double b)
{
    if(a>=b)
        return a;
    return b;
}

int a[100005];
int main()
{
    int n,i,s=0,max=0;
    int h, m;
    scanf("%d",&n);
    for(i=0; i<n; i++)
    {
        scanf("%d %d",&h,&m);
        s=h*60+m;
        a[s]++;
        if(a[s]>max)
            max=a[s];
    }
    cout<<max<<endl;
    return 0;
}


B. Young Table


一开始还以为是求最小的步数来达到通过交换数据使其达到1: for all i, j (1 < i ≤ n; 1 ≤ j ≤ ci) holds ai, j > ai - 1, j ;2: for all i, j (1 ≤ i ≤ n; 1 < j ≤ ci) holds ai, j > ai, j - 1 .的条件的,所以纠结了好久,不知道怎么样才能最小,后面懂了意思,有没有用到直接排序的方法,相对每一行每一列进行排序,结果卡在了列的排序上。赛后想到直接排序就行了,就动手写,终于A掉了。不限制移动次数的话,就直接把原来的数放在应该的位置上就行了。答案多样,但总的移动步数不会超过题目的要求。水了。水题 却被虐了....

#include <iostream>
#include <cstdio>
#include <string>
#include <string.h>
#include <map>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
using namespace std;
int min(int a, int b)
{
    if(a<=b)
        return a;
    return b;
}
int max(int a, int b)
{
    if(a>=b)
        return a;
    return b;
}
double min(double a, double b)
{
    if(a<=b)
        return a;
    return b;
}
double max(double a, double b)
{
    if(a>=b)
        return a;
    return b;
}
struct node
{
    int x, y;
    int num;
} s[100000],sp[100000];
int row[100000];
bool cmp(node a, node b)
{
    return a.num < b.num;
}
int main()
{
    int n;
    int a, b, c;
    cin >> n;
    int k = 1;
    for(int i = 1; i <= n; ++i)
        cin >> row[i];
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 1; j <= row[i]; ++j)
        {
            cin >> s[k].num;
            sp[k].num = s[k].num;
            s[k].x = i;
            sp[k].x = i;
            s[k].y = j;
            sp[k].y = j;
            k++;
        }
    }
    sort(sp+1, sp + k,cmp);
    int sum[100000];
    int kp = 0;
    int cnt = 0;
    /*for(int p = 1; p < k; ++p)
    cout << s[p].num;
    cout << endl;*/
    for(int i = 1; i <= k; ++i)
    {
        if(s[i].num != sp[i].num)
        {
            int xp;
            for( xp = 1; xp <= k; ++xp)
            {
                if(s[xp].num == sp[i].num)
                break;
            }
            sum[kp++] = s[i].x;
            sum[kp++] = s[i].y;
            sum[kp++] = s[xp].x;
            sum[kp++] = s[xp].y;
            swap(s[i].num, s[xp].num);
            cnt++;
        }
    }

    cout << cnt <<endl;
    for(int i = 0; i < kp; i +=4)
    {
            printf("%d %d %d %d\n", sum[i],sum[i+1], sum[i+2], sum[i+3]);
    }
    return 0;
}
我在题目里面用了一个数组来保存每次交换的两个数的坐标,在最后就直接输出就行了。这个也没有特定的顺序,就和自己的交换次序对应就行了。对原来的数组要达到目标要求的话,就直接把所有输入的数变成一个以为的结构体数组,排序就OK了。

C. Primes on Interval

第三题:一开始没有用二分法,就直接加了一个isPrime函数,根据a,b 的取值,每次给出一个l的可取区间a,b+a-1;

取定l后,x给出的范围是a,b-l+1,求素数个数的区间为x,x+l-1;

一开始写的时候WA了,后来直接就上for循环了,交了之后华丽丽的TLE了。看了一下循环次数,改了一个循环的退出时间,又交了一次,又TLE了。又直接把l的取值改成二分得到,继续交,又TLE了。没办法,改素数的判断为直接利用线性筛选素数,交,又是TLE。唉...伤了...继续改善,加上supm数组,计算每一个数前面的素数个数。交,终于A了。华丽丽的一次WA,四次TLE,这....

好吧,上代码:

#include <iostream>
#include <cstdio>
#include <string>
#include <string.h>
#include <map>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
using namespace std;
int min(int a, int b)
{
    if(a<=b)
        return a;
    return b;
}
int max(int a, int b)
{
    if(a>=b)
        return a;
    return b;
}
double min(double a, double b)
{
    if(a<=b)
        return a;
    return b;
}
double max(double a, double b)
{
    if(a>=b)
        return a;
    return b;
}
bool isprime(int a)
{
    if(a==0||a==1)
        return false;
    if(a==2||a==3)
        return true;
    for(int i = 2; i <= sqrt(a); ++i)
    {
        if(a%i==0)
            return false;
    }
    return true;
}
int prime[1000010];
int sump[1000010];
void getprime()//筛选素数
{

    prime[0] = 1;
    prime[1] = 1;
    for(int i = 2; i <=1000000; ++i)
        if(prime[i]==0)
            for(int j = 2*i; j <= 1000000; j+=i)
                prime[j] = 1;
    sump[0] = 0;
    sump[1] = 0;
    for(int i = 2; i <= 1000000; ++i)
    {
        if(prime[i]==0)
            sump[i] = sump[i-1]+1;
        else
            sump[i] = sump[i-1];
    }
}

int main()
{
    memset(prime, 0, sizeof(prime));
    getprime();
    int a, b, k;
    int fp = 0;
    cin >> a >> b >>k;
    int ls = b-a + 1;
    int cnt = 0;
    int ans = 0;
    int lx = 1;
    int l;
    int index = 0;
    while(lx<=ls)
    {
        l = (lx+ls)/2;
        //cout << "l: "<<l <<endl;
        for(int i = a; i <= b-l+1; ++i)
        {
            index = 1;
            if(sump[i+l-1] - sump[i-1] < k)
            {
                //cout << i <<' ' << l << ' ';
                // cout << sump[i-1] <<' '<<sump[i+l-1]<<endl;
                index = 0;
                break;
            }
        }
        if(index)
        {
            fp = 1;
            ls = l-1;
        }
        else
        {
            lx = l+1;
        }
    }
    if(fp)
        cout << lx << endl;
    else
        cout << -1<<endl;

    return 0;
}

T-decomposition

D题一直没太看懂题意,昨天听他们讲了一下。题目的要求就是给你一棵树,把这棵树先拆开,拆成点线的集合,然后再求两个集合之间是否有共同的点,有的话,就说这两个集合相连,输出这两个集合相连的边。
下面这个是转的(上面讲的那个就是下面所说的那种基数最小的情况了,就是把下面解释的s树中的每条边的两个结点( 因为 基数就是它所包含的s树结点的个数) ,作为t树中的新结点 ):

题目大意就是

给了一颗树s,然后让你构造一个树叫t,

t这颗树比较特别,就是这颗树上的结点都是由树s上的若干结点构成的集合。 并且t树上所有结点的并集是s树的结点的全集

并且,如果s上有边(a,b)那么t树上必须有某个结点,包含a和b这两个点。

最后一条,如果t树上有两个结点x,y,若x中包含了s树中的结点a,且y中包含了s树中的结点a,那么t树中,x到y的路径上的结点都必须包含s树中结点a 

然后规定某个结点的基数就是它所包含的s树结点的个数,然后整个树的基数就是所有结点中最大的基数

现在就想让树的基数最小。

最后输出的是t树中每个结点包含了哪些s树中结点,以及t树中的边


比如说树:1 2, 1 3 , 1 4;

划分后就是(1,2),(1,3),(1,4)。这样的话所有的集合当中的基数都是2,输出t树中的每一个节点包含的s树的节点,那么就是(1,2)-包含了点,点。同理(1,3),(1,4)分别是点,点3和点1,点4;然后就是求t树的边。(1,2)和(1,3)就是边1,2了。。。

不过这个stl--vector....

#include <iostream>
#include <cstdio>
#include <string>
#include <string.h>
#include <map>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
using namespace std;

int min(int a, int b)
{
    if(a<=b)
        return a;
    return b;
}
int max(int a, int b)
{
    if(a>=b)
        return a;
    return b;
}
double min(double a, double b)
{
    if(a<=b)
        return a;
    return b;
}

const int N = 100010;
vector<int> v[N];

int main()
{
    int n,x,y;
    scanf("%d",&n);
    printf("%d\n",n - 1);
    for(int i = 1; i < n; i ++)
    {
        scanf("%d%d",&x,&y);
        v[x].push_back(i);
        v[y].push_back(i);
        printf("2 %d %d\n",x,y);
    }
    for(int i = 1; i <= n; i ++)
    {
        for(int j = 1; j < v[i].size(); j ++)
            printf("%d %d\n",v[i][j - 1],v[i][j]);
    }
    return 0;
}

E. Build String

这道题后面知道题意了,费用流,可是木有写过,悲剧了。下面的是转过来的。流着....

题意:给你一个目标串str_t,你可以用下面的n个串(str[N][N]),每个串str[i]中选出limit[i]个字符,从第i个串中拿出一个字符消耗代价是i。问构成这个串最小的代价是多少,如果不能构成这个目标串str_t则输出-1。

设置一个超级源点st和超级汇点ed。超级源点到每个str[i]建立一条容量为limit[i],代价为0的边。将目标串拆成26个字母,根据目标串中有多少个这个字符,建立从这个字符到超级汇点的边,容量即有它的个数,代价也为0。为每个串str[i]中中每个字符建立从这个串str[i]到目标号对应字母的边,容量为1,代价即为i。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#include <set>
#include <map>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;

const int MaxM=200001;
const int INF=(1<<30);

const int N=105;

struct Edge
{
	int u,v,pre,cap,cost;
	Edge(){}
	Edge(int u,int v,int pre,int cap,int cost) :
		u(u),v(v),pre(pre),cap(cap),cost(cost) {}
}edge[MaxM];

int head[MaxM],nEdge,re_flow;

void init()
{
	nEdge=0;
	memset(head,-1,sizeof(head));
}
void addEdge(int u,int v,int cap,int cost)
{
	edge[nEdge]=Edge(u,v,head[u],cap,cost);
	head[u]=nEdge++;
	edge[nEdge]=Edge(v,u,head[v],0,-cost);
	head[v]=nEdge++;
}
struct MinCostFlow
{
	queue<int> que;
	int vis[MaxM],pre[MaxM],dis[MaxM],pos[MaxM];
	int spfa(int s,int t,int n)
	{
		for(int i=0;i<=n;i++)
		{
			pre[i]=-1; vis[i]=0; dis[i]=INF;
		}

		que.push(s); pre[s]=s; dis[s]=0; vis[s]=1;
		while(!que.empty())
		{
			int u=que.front();

			que.pop(); vis[u]=0;

			for(int i=head[u];i!=-1;i=edge[i].pre)
			{
				int v=edge[i].v,cost=edge[i].cost;
				if(edge[i].cap>0&&dis[u]+cost<dis[v])
				{
					dis[v]=dis[u]+cost;

					pre[v]=u; pos[v]=i;

					if(!vis[v])
					{
						vis[v]=1;
						que.push(v);
					}
				}
			}
		}
		if(pre[t]!=-1&&dis[t]<INF) return 1;
		return 0;
	}
	void solve(int s,int t,int n,int &flow,int &cost)
	{
		flow=0,cost=0;
		while(spfa(s,t,n))
		{
			int mi=INF;
			for(int u=t;u!=s;u=pre[u]) mi=min(mi,edge[pos[u]].cap);
			flow+=mi;
			cost+=mi*dis[t];
			for(int u=t;u!=s;u=pre[u])
			{
				edge[ pos[u] ].cap-=mi;
				edge[ pos[u]^1 ].cap+=mi;
			}
		}
	}
}flow;


void input(int &st,int &ed)
{
    int n,len,limit[N],cnt[30]={0};
    char str_t[N],str[N][N];

    scanf("%s %d",str_t,&n);

    st=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%s %d",str[i],&limit[i]);

        addEdge(st,i,limit[i],0);

        len=(int)strlen(str[i]);
        for(int j=0;j<len;j++)
        {
            addEdge(i,n+str[i][j]-'a'+1,1,i);
        }
    }

    re_flow=len=(int)strlen(str_t);

    for(int i=0;i<len;i++)
    {
        cnt[str_t[i]-'a']++;
    }
    ed=n+31;

    for(int i=0;i<30;i++)
    {
        if(cnt[i]) addEdge(n+i+1,ed,cnt[i],0);
    }
}
int main()
{
    init();
    int st,ed,mx_flow,cost;
    input(st,ed);
    flow.solve(st,ed,ed-st+1,mx_flow,cost);
    if(mx_flow!=re_flow) cout<<-1<<endl;
    else cout<<cost<<endl;
    return 0;
}

努力努力....




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值