比赛地址在http://poj.openjudge.cn/challenge3/
A. table
要想满足尽可能多的小组要求,肯定是按照小组中人数的升序来逐个满足。周长满足的策略可以采用贪心法,注意到每增加一个正方形周长加2;每增加一个等边三角形周长增加1;因此三角形的灵活性相对更大,应当优先用正方形(在同等情况下)。
int main(){
int a, b, n;
int arr[10005];
while(cin>>n>>a>>b){
for(int i=0; i<n; i++)
cin>>arr[i];
sort(arr, arr+n);
int res = 0;
bool all = true;
for(int i=0; i<n; i++){
if(a==0 && b==0){
res = i;
all = false;
break;
}
if(arr[i]<=3 && a>0){
a--; continue;
}
if(arr[i]<=4 && b>0){
b--; continue;
}
if(arr[i]>(a+2*b+2)){
res = i;
all = false;
break;
}
int tmp = (arr[i]-2)/2;
if(tmp <= b){
b -= tmp;
if(arr[i]%2 == 1){
if(a>0) a--;
else b--;
}
continue;
}
if(b>0){
arr[i] -= 2*b+2;
b = 0;
a -= arr[i];
continue;
}
if(b==0){
a -= (arr[i]-2);
continue;
}
}
if(all == true) cout<<n<<endl;
else cout<<res<<endl;
}
return 0;
}
B. 如果采用暴力计算的方法,肯定是会超时的。一个很关键的观察,是看到P的取值最大也只有100,进而可以猜想:如果一个区间所包含的元素个数大于等于P,那么最小模和一定是0(不要问我怎么想到的,我也是想了一晚上突然就想到了。。。).证明可以采用鸽巢原理,如果P个元素取模有为0的,那就不用证了;如果都大于0,根据鸽巢原理,至少有两个是相同的,这时把这两个元素中间的子区间取出来,模和便为0;对于区间元素数小于P的情形,由于P最大才100,暴力枚举就行了。
int main(){
int n, m;
int arr[100005];
int tmp[105];
while(cin>>n>>m){
for(int i=0; i<n; i++) scanf("%d", arr+i);
int l, r, p;
for(int i=0; i<m; i++){
scanf("%d%d%d", &l, &r, &p);
l--; r--;
int len = (r-l+1);
if(len >= p){
printf("0\n"); continue;
}
int mn = 1000;
tmp[0] = (arr[l]%p);
for(int j=1; j<len; j++){
tmp[j] = (tmp[j-1]+arr[j+l])%p;
}
for(int j=0; j<len; j++){
for(int k=j; k<len; k++){
mn = min(mn, (tmp[k]-tmp[j]+arr[l+j]+p)%p);
if(mn == 0) break;
}
}
printf("%d\n", mn);
}
}
return 0;
}
C. 这个题目和2SAT比较相似,2SAT问题可以通过构建有向图,利用强连通分量来求解,这个其实没那么复杂,构建出有向图之后(如何添边请自行google),只需要判断a到非a是否有路径可达就行了,判断的方法可以用广搜,反正也就2000个顶点。
const int SIZE = 3005;
int getIndex(int number){
return abs(number)*2+(number < 0);
}
int main(){
int n, m;
vector<int> adj[SIZE];
while(cin>>n>>m){
for(int i=0; i<SIZE; i++)
adj[i].clear();
for(int i=0; i<m; i++){
int node1, node2, no1, no2;
cin>>node1>>node2>>no1>>no2;
if(no1 == 1){
node1 = -node1;
if(no2 == 0) node2 = -node2;
}
else if(no1 == 0){
if(no2 == 0) node2 = -node2;
}
adj[getIndex(-node1)].push_back(getIndex(node2));
adj[getIndex(-node2)].push_back(getIndex(node1));
//radj[getIndex(node2)].push_back(getIndex(-node1));
//radj[getIndex(node1)].push_back(getIndex(-node2));
}
int res = 0;
bool flag[SIZE];
vector<int> goal; goal.clear();
memset(flag, false, sizeof(flag));
for(int i=1; i<=n; i++){
int pos = getIndex(i);
memset(flag, false, sizeof(flag));
queue<int> q;
while(q.empty() == false) q.pop();
q.push(pos); flag[pos] = true;
while(q.empty() == false){
int tmp = q.front(); q.pop();
int len = adj[tmp].size();
for(int j=0; j<len; j++){
if(flag[adj[tmp][j]]==true) continue;
flag[adj[tmp][j]] = true;
q.push(adj[tmp][j]);
}
}
if(flag[pos+1] == true){
res++; goal.push_back(i);
}
}
cout<<res<<endl;
if(res > 0) cout<<goal[0];
for(int i=1; i<goal.size(); i++)
cout<<" "<<goal[i];
cout<<endl;
}
return 0;
}
D还没想明白。。