369DIV2的D题其实是一道比较简单的DP题,但是比赛的时候,被概率吓到了,题目意思都没搞清楚。
画二维表,让分析变得简单了很多。
code:
#include <iostream>
#include <algorithm>
#include <fstream>
#include <cstring>
#include <queue>
using namespace std;
#define N 3000+10
struct node {
int i,j,r;//i,j,j+1,j+2,...,n-1,n
//through r rounds.
node(int q=0,int w=0,int e=0):i(q),j(w),r(e){}
};
int Max[N],p[N],dp[N][N];
int n,k,sum;
int main()
{
//freopen("1.in","r",stdin);
while (scanf("%d%d",&n,&k)!=EOF){
for (int i=1;i<=n;i++) scanf("%d",&p[i]);
Max[n]=p[n];
for (int i=n-1;i;i--) Max[i]=max(Max[i+1],p[i]);
//init
for(int i=1;i<n+2;i++)
for (int j=i+1;j<=n+2;j++)
dp[i][j]=k+1;
dp[1][2]=0;
queue<node> q;
if (2<=n) q.push(node(1,2,0));
sum=1;
while(!q.empty()) {
node now=q.front();
q.pop();
//(i,j)->(j,j+1)
if (p[now.i]<100 && Max[now.j]>0)
if (dp[now.j][now.j+1]>now.r+1) {
sum++;
dp[now.j][now.j+1]=now.r+1;
if (now.j+1<=n && now.r+1<k)
q.push(node(now.j,now.j+1,now.r+1));
}
// (i,j)->(i,j+1)
if (p[now.i]>0 && Max[now.j]<100)
if (dp[now.i][now.j+1]>now.r+1) {
sum++;
dp[now.i][now.j+1]=now.r+1;
if (now.j+1<=n && now.r+1<k)
q.push(node(now.i,now.j+1,now.r+1));
}
//(i,j)->(j+1,j+2)
if (p[now.i]>0 && Max[now.j]>0)
if (dp[now.j+1][now.j+2]>now.r+1) {
sum++;
dp[now.j+1][now.j+2]=now.r+1;
if (now.j+2<=n && now.r+1<k)
q.push(node(now.j+1,now.j+2,now.r+1));
}
}
printf("%d\n",sum);
}
return 0;
}
369DIV2的E题,一道关于树状数组的题。
给定一些线段,然后询问给出cnt个点,问至少包含其中一点的线段总有多少个。
我已开始是把询问的点依次加到树状数组中,然后看线段部分是否覆盖了点,这样复杂度太高,会超时。
看了别人的作法,把询问点先读入,然后离线排序,统计每个询问的相邻两个点(看做一个线段)中是否包含线段,最后n-被包含的线段数,即为答案。
1:用谁来构建树状数组要想好;2:反向考虑,是统计有覆盖的,还是统计完全没覆盖的。
code:
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cstring>
using namespace std;
#define N 1000000+5
#define T 300000+5
#define long long i64
struct node {
int l,r,flag;
};
int cmp(node a,node b)
{
return a.r<b.r;
}
node seg[N],ment[N];
int ans[N],c[N];
int lowbit(int i)
{
return i&(-i);
}
void add(int x)
{
while(x<N){
c[x]++;
x+=lowbit(x);
}
}
int sum(int x)
{
int js=0;
while (x>0) {
js+=c[x];
x-=lowbit(x);
}
return js;
}
int main()
{
//freopen("1.in","r",stdin);
int n,m;
scanf("%d%d",&n,&m);
for (int i=0;i<n;i++)
scanf("%d%d",&seg[i].l,&seg[i].r);
sort(seg,seg+n,cmp);
int cnt=0;
for (int i=1;i<=m;i++) {
int k;
scanf("%d",&k);
for (int j=0;j<k;j++){
scanf("%d",&ment[cnt].r);
if (j==0) ment[cnt].l=0;
else ment[cnt].l=ment[cnt-1].r;
ment[cnt].flag=i;
cnt++;
}
ment[cnt].l=ment[cnt-1].r;
ment[cnt].r=N;
ment[cnt].flag=i;
cnt++;
}
sort(ment,ment+cnt,cmp);
int p=0;
for (int i=0;i<cnt;i++){
while (p<n && seg[p].r<ment[i].r) {
add(seg[p].l);
p++;
}
if (ment[i].r>ment[i].l)
ans[ment[i].flag]+=sum(ment[i].r-1)-sum(ment[i].l);
}
for (int i=1;i<=m;i++)
printf("%d\n",n-ans[i]);
return 0;
}
370DIV2的C题是一道恶搞题吧,理解题目意思就很清楚了,结果比赛的时候又SB了。。
交换手套可以很多人一起,组成一个圈,是否有人无法换到的判断条件是:颜色最多的那组的人数*2>n的话,就有2*人数-n的人无法匹配;否则,都可以匹配。
然后就是想个具体的策略分配方案:我是先把各组颜色横向排列,到才c[0].cnt,截断开始新的一行;输出的时候,按列输出,注意左右手是有区别的,over。
code:
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cstring>
using namespace std;
#define N 100+10
#define T 5000+10
#define long long i64
struct node {
int color,cnt;
};
int cmp(node a,node b){
return a.cnt>b.cnt;
}
node c[N];
int p[N][T];
int n,m;
int main()
{
//freopen("1.in","r",stdin);
scanf("%d%d",&n,&m);
//init
for (int i=0;i<m;i++){
c[i].color=i+1;
c[i].cnt=0;
}
for (int i=0;i<n;i++){
int j;
scanf("%d",&j);
c[j-1].cnt++;
}
sort(c,c+m,cmp);
if (2*c[0].cnt<=n) printf("%d\n",n);
else printf("%d\n",2*(n-c[0].cnt));
int i=0,j=0,mod=c[0].cnt;
for (int k=0;k<m;k++)
while (c[k].cnt>0) {
p[i][j]=c[k].color;
j++;
if (j==mod)
{i++;j=0;}
c[k].cnt--;
}
int x=0,y=0;
p[0][mod]=c[0].color;
for (int i=0;i<n;i++) {
if (p[x+1][y]>0) {
printf("%d %d\n",p[x][y],p[x+1][y]);
p[x][y]=0;
x++;
}
else {
printf("%d %d\n",p[x][y],p[0][y+1]);
p[x][y]=0;
x=0;y++;
}
}
p[0][mod]=0;
return 0;
}
看看今晚能不能把369DIV2的E题想出来。