血虐啊
今天的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
#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
题目大意就是
给了一颗树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;
}
努力努力....