河南省第十一届省赛
感觉这一套题挺好的,很多算法都涉及到了。只是ac的多的题我写不好。。。
A 计划日
写的时候想复杂了,只需年月日的日+需要加的天数,然后处理就好了,不用分别处理月和年了。
#include <stdio.h>
int a[13]={0,31,0,31,30,31,30,31,31,30,31,30,31};
void ra(int yy){
if(yy%400==0||(yy%100!=0&&yy%4==0))a[2]=29;
else a[2]=28;
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
int s,w,n;
scanf("%d%d%d",&s,&w,&n);
int yy,mm,dd;
yy=s/10000;
mm=s/100%100;
dd=s%100;
ra(yy);
int week = (w+n)%7;
if(week==0)week=7;
while(n--){
dd++;
if(dd>a[mm]){
dd=1;
mm++;
}
if(mm==13){
mm=1;
yy++;
ra(yy);
}
}
printf("%d%02d%02d %d\n",yy,mm,dd,week);
}
return 0;
}
B 治安管理
队友cyj大佬写的,看着是模拟题–
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=100005;
const int inf=0x3f3f3f3f;
typedef long long ll;
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n,m,s,f,x;
int a[100001]={0};
scanf("%d%d%d%d",&n,&m,&s,&f);
for(int i=0;i<n;i++){
scanf("%d",&x);
a[x]++;
}
for(int i=0;i<n;i++){
scanf("%d",&x);
a[x]--;
}
int min,max;
if(s==0){
min=a[0];
max=a[0];
}else{
min=n+1;
max=0;
}
for(int i=1;i<f;i++){
a[i]+=a[i-1];
if(i>=s){
if(a[i]>max)max=a[i];
if(a[i]<min)min=a[i];
}
}
if(min>=m){
printf("YES %d\n",max);
}else{
printf("NO %d\n",min);
}
}
return 0;
}
C 山区修路
dp还是不会。。。
暴力dp,第一座山处理之后,后面的山费用由前一座山的高度推出,求两座山的自身高度到最高高度时需要填补的费用和补坡的费用。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=100005;
const int inf=0x3f3f3f3f;
typedef long long ll;
int T,n,m,ans;
int a[N],dp[N][105];
int main()
{
int T,x,i,h1,h2;
scanf("%d",&T);
while(T--){
memset(dp,inf,sizeof(dp));
scanf("%d %d",&n,&x);
int mx=0;
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
if(a[i]>mx) mx=a[i];
}
for(i=a[1];i<=mx;i++){ //初始化第一个山,求它到最高高度分别需要多少费用
dp[1][i]=(i-a[1])*(i-a[1]);
}
for(i=2;i<=n;i++) //列举2~n山
for(h1=a[i-1];h1<=mx;h1++)//i-1山的高度
for(h2=a[i];h2<=mx;h2++){//i山的高度
dp[i][h2]=min(dp[i][h2],dp[i-1][h1]+(h2-a[i])*(h2-a[i])+(int)abs(h2-h1)*x);
//第i山的h2高度的费用,由前一座山h1高度的费用+i山补的高度费用+两座山坡的费用推出
}
ans=inf;
for(i=a[n];i<=mx;i++)
ans=min(ans,dp[n][i]);
printf("%d\n",ans);
}
return 0;
}
D 求XF+闭包(待补)
E 物流配送
可能我对模板题有点误解。。。我太菜了看了一会才看出来是最小费用流,而且知道后并不清楚怎么改。。。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=5e4+10;
const int inf=0x3f3f3f3f;
typedef long long ll;
int T,n,m,ans,st,en;
struct node{
int to,next,flow,dis;
}s[N];
int head[N],num=1,maxflow,mincost;
int a[N],b[N];
int dis[N],minf[N],pre[N];
void add(int u,int v,int w,int cap){
s[++num]=(node){v,head[u],w,cap};
head[u]=num;
}
int spfa(){
memset(dis,inf,sizeof(dis));
int vis[N]={0};
vis[st]=1;
minf[st]=1<<30;
dis[st]=0;
queue<int>q; q.push(st);
while(!q.empty()){
int u=q.front(); q.pop();
vis[u]=0;
for(int i=head[u];i;i=s[i].next){
if(!s[i].flow) continue;
int v=s[i].to;
if(dis[v]>dis[u]+s[i].dis){
dis[v]=dis[u]+s[i].dis;
minf[v]=min(minf[u],s[i].flow);
pre[v]=i;
if(!vis[v]){
vis[v]=1;q.push(v);
}
}
}
}
return dis[en]!=inf;
}
void MCMF(){
while(spfa()){
int cur=en;
maxflow+=minf[en];
mincost+=minf[en]*dis[en];
while(cur!=st){
int fa=pre[cur];
s[fa].flow-=minf[en];
s[fa^1].flow+=minf[en];
cur=s[fa^1].to;
}
}
}
int main()
{
int i,j,k,x,y,z;
cin>>n;
st=0;en=n+1;
for(i=1;i<=n;i++) {
scanf("%d",&x);
add(0,i,x,0);//起点到各个点的流量
add(i,0,0,0);
}
for(i=1;i<=n;i++) {
scanf("%d",&x);
add(i,n+1,x,0);//各个点到终点的流量
add(n+1,i,0,0);
}
for(i=1;i<n;i++){
cin>>x>>y>>k;
add(x,y,inf,k);//给出的边流量无限,无向图的费用正反都一样
add(y,x,inf,k);
}
MCMF();//剩下的模板不用改
cout<<mincost;
return 0;
}
F Gene mutation
开始题没读懂并不知道怎么搞。。。
要翻转是长串,题目要求子串的递增差值是否和长串任意一段是否匹配,长串取出子串长度然后排序比较。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
using namespace std;
const int N=20005;
const int inf=0x3f3f3f3f;
int x[N],y[N],a[N];
int main()
{
int T,n,i,j,m,k,c;
scanf("%d",&T);
while(T--){
int ans=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&x[i]);
scanf("%d",&c);
for(i=1;i<=c;i++)
scanf("%d",&y[i]);
sort(y+1,y+1+c);
for(i=1;i<c;i++)
y[i]=y[i+1]-y[i];
for(i=1;i<=n-c+1;i++){
for(j=i;j<i+c;j++){
a[j-i+1]=x[j];
}
sort(a+1,a+1+c);
int f=0;
for(j=1;j<c;j++){
// printf("%d ",a[j+1]-a[j]);
if(a[j+1]-a[j]!=y[j]){
f=1;break;
}
}
if(!f) ans++;
// printf("\n");
}
printf("%d\n",ans);
}
return 0;
}
G Checkpoints
感觉这题比上一题简单多了,这才是bfs裸题,但是写出来的人比上一题少好多。
两点之间的最短路,bfs无疑了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N=105;
const int inf=0x3f3f3f3f;
typedef long long ll;
int T,n,m,ans,a,b;
vector<int>v[N];
int vis[N];
struct node{
int x,cnt;
}s,t;
void bfs(){
queue<node>q;
s.x=a; s.cnt=0;
vis[a]=1;
q.push(s);
while(!q.empty()){
t=q.front(); q.pop();
//printf("%d ",t.x);
if(t.x==b) {
printf("%d",t.cnt); return ;
}
s.cnt=t.cnt+1;
for(int i=0;i<v[t.x].size();i++){
int to=v[t.x][i];
if(vis[to]==0){
vis[to]=1;
s.x=to;
q.push(s);
}
}
}
}
int main()
{
int i,j,k,x,y;
scanf("%d",&T);
while(T--){
scanf("%d %d %d %d",&n,&m,&a,&b);
while(m--){
scanf("%d %d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
bfs();
}
return 0;
}
H Attack City and Capture Territory
尼姆博弈模板,异或和为0时先手输,否则先手赢。
很好理解,异或和为0时,有n堆物品,n%2==0,并且一定能找到两个数量一样多的堆。先手拿一堆中的任意数量物品时,后手在对应堆也拿相同数量的物品,后手是最后拿物品的人,此时后手必赢
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=100005;
const int inf=0x3f3f3f3f;
typedef long long ll;
int T,n,m,ans;
int a[N],dp[N][105];
int main()
{
int T,x,i,h1,h2;
scanf("%d",&T);
while(T--){
ans=0;
scanf("%d",&n);
while(n--){
scanf("%d",&x);
ans^=x;
}
if(ans==0) puts("Liu_B is not sure to win.");
else puts("Liu_B is sure to win.");
}
return 0;
}