跳过正文
  1. Posts/

codeforces 314 D One-Dimensional Battle Ships (模拟)

·2 分钟

比赛的时候没搞出来,really sad. 其实这题很容易啊.... 首先,对于lie 的判断应该基于能放的船的个数. 能放的船的个数是随着射的点数的增加而减少的. 射完每个点后更新能放的船的个数,如果这个时候已经无法放下k条船了,说明lie了. 如果所有都射完也没发生,那么就-1.

由于船与串不能相邻,除了最后一条船,每条船实际占的size 应该为a+1 那么很容易知道对于长度为l的区间,能放的船的个数为(l+1)/(a+1) 这是初始能放的船的个数,为最大值. 当射了点b之后,破坏的是b所在的一段最大的没有被射过点的区间的连续性. 做法是找到距离b点最近的左端和右端的被射过的点. 可以用set 搞,找的时候upper_bound 记得初始化的时候把 0点和 n+1 点当成射过的.

 1/*************************************************************************
 2	> File Name: code/cf/#314/D.cpp
 3	> Author: 111qqz
 4	> Email: rkz2013@126.com
 5	> Created Time: 2015年08月16日 星期日 00时27分54秒
 6 ************************************************************************/
 7
 8#include<iostream>
 9#include<iomanip>
10#include<cstdio>
11#include<algorithm>
12#include<cmath>
13#include<cstring>
14#include<string>
15#include<map>
16#include<set>
17#include<queue>
18#include<vector>
19#include<stack>
20#define y0 abc111qqz
21#define y1 hust111qqz
22#define yn hez111qqz
23#define j1 cute111qqz
24#define tm crazy111qqz
25#define lr dying111qqz
26using namespace std;
27#define REP(i, n) for (int i=0;i<int(n);++i)
28typedef long long LL;
29typedef unsigned long long ULL;
30const int inf = 0x7fffffff;
31set<int> se;
32int n,k,a,m,b;
33set<int>::iterator it;
34int cal (int x,int y)  //cal 函数计算出当射了b之后,因此减少的能放船的个数.
35{
36    int res;
37    res = (y-x)/(a+1)-(y-b)/(a+1)-(b-x)/(a+1);//由于射了b点,相当于之前连续的区间(x,y)被分成了(x,b)和(b,y)
38						  //(x,y)区间能放的船的数量由之前变成了被分成的两个小区间能放的船的数量的和.
39    return res;
40}
41int main()
42{
43	scanf("%d %d %d",&n,&k,&a);
44	scanf("%d",&m);
45	se.clear();
46	int sum=(n+1)/(a+1); //sum表示的是当前能放的船的个数
47			    //容易知道,对于长度为l的点,最多能放的船的数量为(l+1)/(a+1);
48	se.insert(0);
49	se.insert(n+1);//由于要找要被射的点两遍最近的被射的点,我们不妨认为0点和n+1点也是被射的,这样处理断点容易些.
50	int ans = -1;
51	bool flag = false;
52	for (int i=1;i<=m;i++)
53	{
54	    scanf("%d",&b);
55	    if (flag) continue;
56	    it=se.upper_bound(b);
57	    int y=*it;
58	    int x=*(--it);   //y和x分别是离b点最近且已经被射的点
59	    sum = sum - cal(x,y);
60	    if (sum<k)
61	    {
62		ans =  i;
63		flag = true;
64	    }
65	    se.insert(b);
66	}
67	cout<<ans<<endl;
68	return 0;
69}

相关文章

hdu 1050 Moving Tables

·1 分钟
一开始算法想的有点问题。 坑点在于走廊两侧都有房间 也就是说room1和room2对应的位置是一样的

hdu 5113 Black And White

·3 分钟
题意是说用k重颜色填充n*m的方格,第i种颜色要用ci次,保证ci(i属于1..k)的和为n"m,问是否有可行解,若有,输出任意一种。 第一感觉是dfs.。。而且数据范围还那么小。但是鉴于我上次dfs写成汪的经历….嗯 不过群里有学长说似乎剪枝不太好想? 我一开始分了四类,o行o列,e行e列,e行o列,o行e列,(o是odd,e是even)然后将c[i]排序,先填大的C[I],感觉这样应该更容易找到解。交了一发,WA掉了。。发现当k较小的时候,也就是c[i]都相对较大的时候,先填大的C[I]的策略会出现错误。于是我换了下….按c[i]的大小从两边往中间…然后我还发现其实o行o列和e行e列可以归为一类,同理,后两种也可以归为一类。又交,又WA2333333 然后想了好久。。。 发现对于上面说的两类的处理顺序不同会得到不同的结果…….只有一种是对的。于是加了个judge函数判断冲突…如果冲突就换个顺序…..再交,A了。

codeforces 569 E. New Language (2-sat)

·2 分钟
1/************************************************************************* 2 > File Name: code/cf/#315/E.cpp 3 > Author: 111qqz 4 > Email: rkz2013@126.com 5 > Created Time: 2015年08月15日 星期六 13时48分36秒 6 ************************************************************************/ 7#include<iostream> 8#include<iomanip> 9#include<cstdio> 10#include<algorithm> 11#include<cmath> 12#include<cstring> 13#include<string> 14#include<map> 15#include<set> 16#include<queue> 17#include<vector> 18#include<stack> 19#define y0 abc111qqz 20#define y1 hust111qqz 21#define yn hez111qqz 22#define j1 cute111qqz 23#define tm crazy111qqz 24#define lr dying111qqz 25using namespace std; 26#define REP(i, n) for (int i=0;i<int(n);++i) 27typedef long long LL; 28typedef unsigned long long ULL; 29const int inf = 0x7fffffff; 30const int N=5E2+7; 31int flag[N],flag2[N]; 32int f[N][N]; 33int a[N]; 34char s[N]; 35int ans[N]; 36int len,n,m; 37char s1[13],s2[13]; 38int p1,p2,q1,q2,dq1,dq2; 39void add(int p,int q,int flag[]) 40{ 41 int dq = q * n + p;//找到元辅音状态为q,第p的点的下标 42 for (int i=1;i<=2*n;++i) 43 { 44 if (f[dq][i]==0) continue; 45 flag[i]=1;//找到所有由dp出发的边指向的点,表示选了dp点一定要选的点。 46 } 47} 48bool check(int flag[]) 49{ 50 for (int i=1;i<=n;++i) 51 if (flag[i]==1&&flag[i+n]==1) return false; //判断是否存在矛盾 52 //(选了j点后,既要选择某点k的元音,也要选择某点k的辅音) 53 return true; 54} 55bool dfs(int pos,int x) 56{ 57 if (pos>n) return true;//如果能形成一个长度为n的单词,说明这种语言有word 58 bool g[2]; 59 g[0]=g[1]=false; 60 for (int i=x;i<=len;++i)//从当前字母x往后枚举 61 { 62 for (int j=1;j<=2*n;++j) flag2[j]=flag[j];//为了不影响原始数组,复制一个布尔数组出来。 63 add(pos,a[i],flag2);//找到所有选了pos点一定要选的点 64 if (check(flag2)&&(!g[a[i]])) 65 { 66 g[a[i]]=true; 67 for (int j=1;j<=2*n;++j) flag[j]=flag2[j]; 68 ans[pos]=i;//将第pos位置的字母变成i 69 if (dfs(pos+1,1)) return true; 70 else return false;//只要有一位找不到合适的字母形成单词,那么肯定就构不成单词。 71 } 72 } 73 return false; 74} 75int main() 76{ 77 scanf("%s",s); 78 len=strlen(s); //0表示辅音,1表示原因,下同。 79 for (int i=1;i<=len;++i)//len 表示字母表中一共有的字母的个数 80 { 81 if (s[i-1]=='V') 82 { 83 a[i] = 0; 84 } 85 else 86 { 87 a[i] = 1; 88 } 89 } 90 memset(f,0,sizeof(f)); 91 scanf("%d%d",&n,&m); 92 for (int i=1;i<=m;++i)//1..n表示元音的点,n+1..2*n 表示辅音的点 93 { 94 scanf("%d",&p1); 95 scanf("%s",s1); 96 if (s1[0]=='V') q1=0;else q1=1; 97 scanf("%d",&p2); 98 scanf("%s",s2); 99 if (s2[0]=='V') q2=0;else q2=1; 100 dq1=q1*n+p1;dq2=q2*n+p2;//找到这组关系对应的点。 101 f[dq1][dq2]=1;//连一条由dq1指向dq2的边,表示如果选了dp1点,那么一定选dp2点 102 dq1=(1-q2)*n+p2;dq2=(1-q1)*n+p1;//找到逆否命题对应的点 103 // ("如果选1,一定选2"的逆否命题是,"如果不选2,一定不选1") 104 f[dq1][dq2]=1; //在连一条边 105 } 106 for (int i=1;i<=2*n;++i) f[i][i]=1; 107 for (int k=1;k<=2*n;++k)//floyd ,把所有间接相连的边直接相连 108 { 109 for (int i=1;i<=2*n;++i) 110 for (int j=1;j<=2*n;++j) 111 f[i][j]|=f[i][k]&f[k][j]; 112 } 113 scanf("%s",s+1); 114 bool ok=false; 115 for (int i=n;i>=0;--i) //倒着扫,每次只改变最后一位的字母,字母从小往大枚举 //这样就可以保证字典序最小。 116 { 117 memset(flag,0,sizeof(flag)); 118 for (int j=1;j<=i;++j) 119 { 120 add(j,a[s[j]-'a'+1],flag); 121 ans[j]=s[j]-'a'+1; 122 } 123 if (!check(flag)) continue; 124 if (dfs(i+1,s[i+1]-'a'+1+1)) 125 { 126 ok=true; 127 break; 128 } 129 } 130 if (!ok) printf("-1\n"); 131 else 132 { 133 for (int i=1;i<=n;++i) printf("%c",ans[i]+'a'-1); 134 } 135 return 0; 136}