福州大学第十一届程序设计竞赛 部分题目题解
2014-04-27 20:19
465 查看
比赛链接:http://acm.fzu.edu.cn/contest/index.php?cid=139
当今天下午我知道有这个比赛的时候,比赛已经开始20分钟了。。。。
中午早睡早起本来是准备复习考试的,结果比赛以及赛后补题消耗了大量时间,搞得我现在有一种要挂科的预感。。。。
这里还有一份题解:http://blog.csdn.net/ok_again/article/details/24595453
我后面的D题的代码就是参考它的。
第七题后来也过了,比赛时已经基本想出来了,但不知道为什么就是过不了,赛后学长讲给我思路发现出入不大。学长用了n次 Ctrl+Z 之后终于是找到了它的代码,对拍,发现自己写矩阵时有一个细节以前没注意到:
当进行快速幂的时候应该将新矩阵对角线初始化为1,这样矩阵相乘时才能保持不变(这句是写给自己看的,大家写法不同不必深究)。
当矩阵相乘的时候应该将对角线初始化为0,因为需要一个全新的矩阵来存储数据!
FZU 2167 大王叫我来巡山呐
FZU 2168 防守阵地 I
这个题需要推导一下递推关系,推出来直接实现就好了,没什么陷阱
FZU 2169 shadow
DFS即可解决,回溯的时候将多加的部分减掉。
记得需要双向加边,所以边数组需要2倍大小。DFS时传递父节点避免搜回去。
FZU 2170 花生的序列
这个题当时没有做出来。
dp[i][j],表示到第i为为止,有j个属于第一个串,因为串的特殊性(WBWBWB),所以很容易判断当前位置的字母满足的情况。比如当前j为奇数,那么j后面肯定只能接B。
使用滚动数组节省内存。
FZU 2171 防守阵地 II
线段树和树状数组都可以处理,和Hdu3468 (也有可能是POJ……)基本一样。神奇的是交C++过不了,交G++就过了……
Hdu 2173 Nostop
这题算是组合数学中矩阵的一种应用吧,快速幂的新姿势,同时处理两个矩阵……看别人的代码貌似一个也行。
代码感觉写的还是有点挫的……刷点类似的题之后一起优化吧
当今天下午我知道有这个比赛的时候,比赛已经开始20分钟了。。。。
中午早睡早起本来是准备复习考试的,结果比赛以及赛后补题消耗了大量时间,搞得我现在有一种要挂科的预感。。。。
1 | 大王叫我来巡山呐 | 80.31%(261/325) | |
2 | 防守阵地 I | 23.48%(193/822) | |
3 | shadow | 13.23%(97/733) | |
4 | 花生的序列 | 12.07%(21/174) | |
5 | 防守阵地 II | 14.98%(68/454) | |
6 | 巡了南山我巡北山 | 0.00%(0/45) | |
7 | Nostop | 20.79%(21/101) | |
8 | 卷福的难题 | 10.00%(1/10) |
我后面的D题的代码就是参考它的。
第七题后来也过了,比赛时已经基本想出来了,但不知道为什么就是过不了,赛后学长讲给我思路发现出入不大。学长用了n次 Ctrl+Z 之后终于是找到了它的代码,对拍,发现自己写矩阵时有一个细节以前没注意到:
当进行快速幂的时候应该将新矩阵对角线初始化为1,这样矩阵相乘时才能保持不变(这句是写给自己看的,大家写法不同不必深究)。
当矩阵相乘的时候应该将对角线初始化为0,因为需要一个全新的矩阵来存储数据!
FZU 2167 大王叫我来巡山呐
#include <cstdio> int main () { int n; while (~scanf("%d",&n)) { int sum=n/7*2; int last=n%7; if (last==6) sum++; printf("%d\n",sum); } return 0; }
FZU 2168 防守阵地 I
这个题需要推导一下递推关系,推出来直接实现就好了,没什么陷阱
#include <cstdio> #include <cstring> #define upmax(a,b) ((a)=(a)>(b)?(a):(b)) const int N=1000005; long long data ; long long sum ; int main () { int n,m; while (~scanf("%d%d",&n,&m)) { memset(data,0,sizeof(data)); memset(sum,0,sizeof(sum)); long long i,tmp,ji=0; for (i=0;i<n;i++) { scanf("%lld",&data[i]); if (i==0) sum[i]=data[i]; else sum[i]=sum[i-1]+data[i]; if (i<m) ji+=data[i]*(i+1); //值 } long long tot=ji; for (i=m;i<n;i++) { tmp=sum[i-1]-sum[i-1-m]; ji=ji-tmp+data[i]*m; if (tot<ji) upmax(tot,ji); } printf("%lld\n",tot); } return 0; }
FZU 2169 shadow
DFS即可解决,回溯的时候将多加的部分减掉。
记得需要双向加边,所以边数组需要2倍大小。DFS时传递父节点避免搜回去。
#include <cstdio> #include <cstring> #define min(x,y) ((x)<(y)?(x):(y)) #define max(x,y) ((x)>(y)?(x):(y)) using namespace std; const int N=100005; bool good ; //有军队 int bad ; //敌军数量 long long sum=0; int head ,e; struct Edge { int v,next; }edges[2*N]; int DFS (int u,int val,int father) {//当前点,当前累计价值,父节点 if (good[u]) { sum+=val; } int son=0; if (good[u]) son++; for (int i=head[u];i != -1; i=edges[i].next) if (edges[i].v!=father) son+=DFS(edges[i].v,val+bad[u],u); if (son>1) sum-=(son-1)*bad[u]; return son; } void Add (int u,int v) { edges[e].v=v; edges[e].next=head[u]; head[u]=e++; } int main () { int n,k; while (~scanf("%d%d",&n,&k)) { memset(good,false,sizeof(good)); memset(bad,0,sizeof(bad)); memset(head,-1,sizeof(head)); int i,a; for (i=1;i<=n;i++) scanf("%d",&bad[i]); for (i=0;i<k;i++) { scanf("%d",&a); good[a]=true; } sum=0; for (i=0;i<n-1;i++) { int u,v; scanf("%d%d",&u,&v); Add(u,v); Add(v,u); } int son=0; DFS(1,0,-1); printf("%lld\n",sum); } return 0; }
FZU 2170 花生的序列
这个题当时没有做出来。
dp[i][j],表示到第i为为止,有j个属于第一个串,因为串的特殊性(WBWBWB),所以很容易判断当前位置的字母满足的情况。比如当前j为奇数,那么j后面肯定只能接B。
使用滚动数组节省内存。
#include <cstdio> #include <cstring> const int N = 10005; const int INF = 0x3f3f3f3f; const int MOD = 1000000007; char str ; int dp[2][3300]; //dp[i][j],表示到第i个字母为止,有j个属于第一个串 int main () { int T, n; scanf("%d", &T); while (T --) { scanf("%d%s", &n, str); memset(dp,0,sizeof(dp)); dp[0][0]=1; for (int i=0,t=1; i<2*n; i++,t++) { memset(dp[t&1],0,sizeof(dp[0])); if (str[i]=='B') for (int j=0;j<=n;j++) { if (j&1) //奇数 dp[t&1][j+1] = (dp[t&1][j+1] + dp[i&1][j]) % MOD; if ((i-j)&1) dp[t&1][j] = (dp[t&1][j] + dp[i&1][j]) % MOD; } else for (int j=0;j<=n;j++) { if ((j&1) == 0) dp[t&1][j+1] = (dp[t&1][j+1] + dp[i&1][j]) % MOD; if (((i-j)&1) == 0) dp[t&1][j] = (dp[t&1][j] + dp[i&1][j]) % MOD; } } printf("%d\n", dp[0] ); } return 0; }
FZU 2171 防守阵地 II
线段树和树状数组都可以处理,和Hdu3468 (也有可能是POJ……)基本一样。神奇的是交C++过不了,交G++就过了……
#include <cstdio> #include <cstring> struct Node { int left,right; long long add,sum; }a[800005]; int n,Q; void Build (int t,int left,int right) { a[t].left=left; a[t].right=right; a[t].add=a[t].sum=0; if (left==right) return; int mid=(left+right)>>1; Build(t*2,left,mid); Build(t*2+1,mid+1,right); } void Insert (int t,int target,int val) { a[t].sum+=val; if (a[t].left==target && a[t].right==target) return; int mid=(a[t].left+a[t].right)>>1; if (target<=mid) Insert(t*2,target,val); else Insert(t*2+1,target,val); } void Add (int t,int left,int right,int add) { if (a[t].left==left && a[t].right==right) { a[t].add+=add; return; } a[t].sum+=(right-left+1)*add; int mid=(a[t].left+a[t].right)>>1; if (right<=mid) Add(t*2,left,right,add); else if (left>mid) Add(t*2+1,left,right,add); else { Add(t*2,left,mid,add); Add(t*2+1,mid+1,right,add); } } long long Query (int t,int left,int right) { if (a[t].left==left && a[t].right==right) return a[t].sum+(a[t].right-a[t].left+1)*a[t].add; int mid=(a[t].left+a[t].right)>>1; Add (t*2,a[t].left,mid,a[t].add); Add (t*2+1,mid+1,a[t].right,a[t].add); a[t].sum+=(a[t].right-a[t].left+1)*a[t].add; a[t].add=0; if (right<=mid) return Query(t*2,left,right); else if (left>mid) return Query(t*2+1,left,right); else return Query(t*2,left,mid)+Query(t*2+1,mid+1,right); } int main () { int m; while (~scanf("%d%d%d",&n,&m,&Q)) { memset(a,0,sizeof(a)); Build (1,1,n); int i,L,R,x; for (i=1;i<=n;i++) { scanf("%d",&x); Insert(1,i,x); } for (i=1;i<=Q;i++) { scanf("%d",&L); R=L+m-1; printf("%lld\n",Query(1,L,R)); Add(1,L,R,-1); } } return 0; }
Hdu 2173 Nostop
这题算是组合数学中矩阵的一种应用吧,快速幂的新姿势,同时处理两个矩阵……看别人的代码貌似一个也行。
代码感觉写的还是有点挫的……刷点类似的题之后一起优化吧
#include <map> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define Upmin(a,b) ((a)=(a)<(b)?(a):(b)) const int N=55; class Matrix { public: bool a ; //保存是否可达 long long cost ; //保存最小花费 int n; //矩阵大小 void init (int _n,int x) { n=_n; memset(a,false,sizeof(a)); if (x) for (int i=0;i<N;i++) a[i][i]=true; for (int i=0;i<N;i++) for (int j=0;j<N;j++) cost[i][j]=((long long)1<<60); } Matrix operator * (Matrix b) { Matrix p; p.init(b.n,0); for (int i=0;i<n;i++) for (int j=0;j<n;j++) { for (int k=0;k<n;k++) { if (a[i][k] && b.a[k][j]) { p.a[i][j]=true; Upmin(p.cost[i][j],cost[i][k]+b.cost[k][j]); } } } return p; } Matrix power (int t) { Matrix ans,p=*this; ans.init(p.n,1); bool flag=false; while (t) { if (t&1) { if (flag==false) ans=p,flag=true; else ans=ans*p; } p=p*p; t>>=1; } return ans; } }a; int main () { int T,n,h,k; scanf("%d",&T); while (T--) { scanf("%d%d%d",&n,&h,&k); a.init (n,0); for (int i=0;i<h;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); u--,v--; a.cost[u][v]=w; a.a[u][v]=true; } a=a.power(k); if (a.a[0][n-1]==false) puts("-1"); else printf("%lld\n",a.cost[0][n-1]); } return 0; }
相关文章推荐
- 福州大学第十二届程序设计竞赛 (部分题解)
- 湖南省第十一届大学生计算机程序设计竞赛 部分题解 待续
- 福州大学第十一届程序设计竞赛
- 福州大学第十一届程序设计竞赛E fzuoj2171(线段树)
- NENU ACM 13级训练赛 2014-12-06(福州大学第十一届程序设计竞赛)
- 福州大学第十一届程序设计竞赛
- 福州大学第十一届程序设计竞赛
- 福州大学第十届程序设计竞赛 -- 部分题解
- 2017年上海金马五校程序设计竞赛(网上资格赛)部分题目题解
- 福州大学第十一届程序设计竞赛
- 挑战程序设计竞赛里面的部分题目<用java写的>
- 湖南第十一届大学生程序设计大赛:多边形的公共部分(多边形面积并)
- HNNU 11658 阶乘除法【湖南省第十一届大学生计算机程序设计竞赛,数论】
- 挑战程序设计竞赛 部分和问题
- FZU 2254 英语考试 (最小生成树)(福州大学第十四届程序设计竞赛)
- 2012年"浪潮杯"山东省第三届ACM大学生程序设计竞赛 The Best Seat in ACM Contest 看清题目后,我是真哭了。。。。。
- foj Problem 2232 炉石传说 福州大学第十三届程序设计竞赛_重现 二分图
- 福州大学第十届程序设计竞赛+Problem C 数字的孔数
- 第十一届北京师范大学程序设计竞赛(网络同步赛)+沙漠之旅
- 福州大学第十二届程序设计竞赛—完美数字