高2018级NOIP模拟赛20190813
作者:互联网
文章目录
非做顽石不可,哪管他敬仰暗唾。堕尘泥,桃源藏胸,仗剑执花如昨
写在前面
这次考试大意啦>_<,最后一道题错的不应该呀,dp很简单的
T1 异或求值
传送门:mzoj #31
题目
描述
求1到n的异或值,即123…^n
输入
一个数n
输出
一个数,表示所求出的值
样例
输入
3
输出
0
数据范围
50% 1<=n<=10^6
100% 1<=n<=10^18
分析
打表找规律,也可以自己证
O(1)
代码
/*************************
User:Mandy.H.Y
Language:c++
Problem:xor
Algorithm:
*************************/
#include<bits/stdc++.h>
#define Max(x,y) ((x) > (y) ? (x) : (y))
#define Min(x,y) ((x) < (y) ? (x) : (y))
using namespace std;
typedef long long ll;
ll n;
template<class T>inline void read(T &x){
x = 0;bool flag = 0;char ch = getchar();
while(!isdigit(ch)) flag |= ch == '-',ch = getchar();
while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
if(flag) x = -x;
}
template<class T>void putch(const T x){
if(x > 9) putch(x / 10);
putchar(x % 10 | 48);
}
template<class T>void put(const T x){
if(x < 0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("xor.in","r",stdin);
freopen("xor.out","w",stdout);
}
void readdata(){
read(n);
}
void work(){
ll res = n % (ll)4;
switch(res){
case 0:{put(n);break;}
case 1:{put(1);break;}
case 2:{put(n + 1);break;}
default:{put(0);break;}
}
}
int main(){
// file();
readdata();
work();
return 0;
}
T2 染色方案
传送门:luogu3914
题目
描述
有一颗N 个节点的树,节点用1, 2…N 编号。你要给它染色,使得相邻节点的颜色不同。有M 种颜色,用1,2…M 编号。每个节点可以染M 种颜色中的若干种,求不同染色方案的数量除以(10^9 + 7)的余数。
输入(color.in)
第1 行,2 个整数N,M,接下来N 行,第i 行表示节点i 可以染的颜色。第1个整数ki,表示可以染的颜色数量。接下来ki个整数,表示可以染的颜色编号。最后N-1 行,每行2个整数Ai,Bi表示边(Ai,Bi)。
输出(color.out)
一行一个数,即答案
样例
输入
2 2
1 1
2 1 2
1 2
输出
1
数据范围
对于30% 的数据, 1<=N<=10; 1<=M<=4;
对于60% 的数据, 1<=N<=200; 1<=M<=200;
对于100% 的数据,1<=N<=5000; 1<=M<=5000 1<=ki 所有ki的和<=1000000
分析
树形DP,这种方案计数一般和乘法原理与加法原理有点关系诶
从下到上分析;
举个栗子:
在叶节点假如情况是这样的:
则 父节点的方案数:
颜色1:2 * 4 * 2
颜色2:2 * 3 * 2
颜色3:2 * 3 * 2
颜色4:3 * 3 * 3
颜色5:3 * 3 * 3
颜色6:3 * 4 * 3
类比若到了树上任意一点
方案数变必须考虑子树的方案数了,但其实也是一样的,即:
颜色 i 的方案数:
儿子 1 不为颜色 i 的方案总数 * 儿子 1 不为颜色 i 的方案总数 * ……
代码
/*************************
User:Mandy.H.Y
Language:c++
Problem:color
Algorithm:
*************************/
#include<bits/stdc++.h>
#define Max(x,y) ((x) > (y) ? (x) : (y))
#define Min(x,y) ((x) < (y) ? (x) : (y))
using namespace std;
const int maxn = 5005;
const int mod = 1e9 + 7;
typedef long long ll;
int n,m,size,first[maxn];
bool color[maxn][maxn],judge;
int dp[maxn][maxn],cnt[maxn];
struct Edge{
int v,nt;
}edge[maxn << 1];
template<class T>inline void read(T &x){
x = 0;bool flag = 0;char ch = getchar();
while(!isdigit(ch)) flag |= ch == '-',ch = getchar();
while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
if(flag) x = -x;
}
template<class T>void putch(const T x){
if(x > 9) putch(x / 10);
putchar(x % 10 | 48);
}
template<class T>void put(const T x){
if(x < 0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("color.in","r",stdin);
freopen("color.out","w",stdout);
}
void eadd(int u,int v){
edge[ ++ size].v = v;
edge[size].nt = first[u];
first[u] = size;
}
void readdata(){
read(n);read(m);
for(int i = 1;i <= n; ++ i){
read(cnt[i]);
if(!cnt[i]) judge = 1;
for(int j = 1;j <= cnt[i]; ++ j) {
int x;
read(x);
color[i][x] = 1;
// dp[i][x] = 1;
}
}
for(int i = 1;i < n; ++ i){
int u,v;;
read(u);read(v);
eadd(u,v);eadd(v,u);
}
}
void dfs(int u,int f){
ll res = 0;
for(int j = first[u];j;j = edge[j].nt){
int v = edge[j].v;
if(v == f) continue;
dfs(v,u);
}
for(int i = 1;i <= m; ++ i){
ll sum = 1;
if(! color[u][i]) continue;
for(int j = first[u];j;j = edge[j].nt){
int v = edge[j].v;
if(v == f) continue;
if(color[v][i]) sum = sum * ((ll)dp[v][0] - dp[v][i] + mod) % mod;
else sum = sum * (ll)dp[v][0] % mod;
}
dp[u][i] = (int)(sum % mod);
res = (res + sum) % mod;
}
dp[u][0] = (int)res;
}
void work(){
dfs(1,0);
put(dp[1][0]);
}
int main(){
// file();
readdata();
if(judge) {
puts("0");
return 0;
}
work();
return 0;
}
T3 新三国争霸
题目传送门:codevs1403
题目
描述 Description
PP 特别喜欢玩即时战略类游戏,但他觉得那些游戏都有美中不足的地方。灾害总不降临道路,而只降临城市,而且道路不能被占领,没有保护粮草的真实性。于是他就研发了《新三国争霸》。
在这款游戏中,加入灾害对道路的影响(也就是一旦道路W[i,j]受到了灾害的影响,那么在一定时间内,这条路将不能通过)和道路的占领权(对于一条道路W[i,j],至少需要K[i,j]个士兵才能守住)。
PP可真是高手,不一会,就攻下了N-1座城市,加上原来的就有N座城市了,但他忽略了一点……那就是防守同样重要,不过现在还来的及。因为才打完仗所以很多城市都需要建设,PP估算了一下,大概需要T天。他现在无暇分身进攻了,只好在这T天内好好的搞建设了。所以他要派士兵占领一些道路,以确保任何两个城市之间都有路(不然敌人就要分而攻之了,是很危险的)。士兵可不是白干活的,每个士兵每天都要吃掉V的军粮。因为有灾害,所以方案可能有变化(每改变一次就需要K的军粮,初始方案也需要K的军粮)。
因为游戏是PP编的,所以他知道什么时候有灾害。PP可是一个很节约的人,他希望这T天在道路的防守上花最少的军粮。
输入格式 InputFormat
第一行有5个整数N,M,T,V,K。N表示有城市数,M表示道路数,T表示需要修养的天数,V表示每个士兵每天吃掉的军粮数,K表示修改一次花掉的军粮数。
以下M行,每行3个数A,B,C。表示A与B有一条路(路是双向的)需要C个士兵才能守住。
第M+2行是一个数P,表示有P个灾害。
以下P行,每行4个数,X,Y,T1,T2。表示X到Y的这条路,在T1到T2这几天都会受灾害。
输出格式 OutputFormat
T天在道路的防守上花费最少的军粮。
样例输入 SampleInput
3 3 5 10 30
1 2 1
2 3 2
1 3 4
1
1 3 2 5
样例输出 SampleOutput
180
数据范围和注释 Hint
对于所有数据:N<=300,M<=5000 ,T<=50,P<=8000
分析
最小生成树 + DP;
用dp[i]表示到第i天总共的最少费用
方程:(ans是第j~i天的共有的最小生成树最低费用)
dp[i]=min(dp[i],dp[j−1]+(i−j+1)∗ans+K
有木有很像[ZJOI2006]物流运输?(有诶>_<)
那个专题传送门:综合题 - 图论与动规
代码
/*************************
User:Mandy.H.Y
Language:c++
Problem:three
Algorithm:
*************************/
#include<bits/stdc++.h>
#define Max(x,y) ((x) > (y) ? (x) : (y))
#define Min(x,y) ((x) < (y) ? (x) : (y))
using namespace std;
const int maxn = 305;
const int maxm = 5005;
int T,N,M,size,V,K,P,now,pre,ans;
int father[maxn];
int dp[55];
bool vis[maxn][maxn];
//因为是按边禁,就标记边而不是点 qwq
struct Val{
int u,v,w;
}val[maxm];
struct Dis{
int x,y,l,r;
}dis[8005];
template<class T>inline void read(T &x){
x = 0;bool flag = 0;char ch = getchar();
while(!isdigit(ch)) flag |= ch == '-',ch = getchar();
while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
if(flag) x = -x;
}
template<class T>void putch(const T x){
if(x > 9) putch(x / 10);
putchar(x % 10 | 48);
}
template<class T>void put(const T x){
if(x < 0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("three.in","r",stdin);
// freopen("three.out","w",stdout);
}
void add(int u,int v,int w){
val[++size].v = v;
val[size].u = u;
val[size].w = w;
}
bool cmp(const Val &a,const Val &b){
return a.w < b.w;
}
bool cmp1(const Dis &a,const Dis &b){
if(a.l != b.l) return a.l < b.l;
else return a.r < b.r;
}
void readdata(){
read(N);read(M);read(T);read(V);read(K);
for(int i = 1;i <= M; ++ i){
int u,v,w;
read(u);read(v);read(w);
add(u,v,w);
}
sort(val + 1,val + 1 + M,cmp);
read(P);
for(int i = 1;i <= P; ++ i){
read(dis[i].x); read(dis[i].y); read(dis[i].l); read(dis[i].r);
}
sort(dis + 1,dis + 1 + P,cmp1);
}
int find(int x){
return father[x] == x ? x : father[x] = find(father[x]);
}
void merge(int x,int y){
father[find(x)] = find(y);
}
int kruskal(int x,int y){
for(int i = 1;i <= N; ++ i) father[i] = i;
memset(vis,0,sizeof(vis));
for(int i = 1;i <= P; ++ i){
if(dis[i].l > y) break;
if(dis[i].l <= y && x <= dis[i].r){
vis[dis[i].x][dis[i].y] = 1;
vis[dis[i].y][dis[i].x] = 1;
}
}
int cnt = 0,cost = 0;
for(int i = 1;i <= M; ++ i){
int v = val[i].v;
int u = val[i].u;
int w = val[i].w;
if(vis[u][v]) continue;
if(find(u) != find(v)){
merge(u,v);
cost += w * V;
++cnt;
}
if(cnt == N - 1) return cost;
}
return -1;
}
void work(){
memset(dp,0x3f3f3f3f,sizeof(dp));
dp[0] = 0;
for(int i = 1;i <= T; ++ i){
for(int j = i;j >= 1; -- j){
int ans = kruskal(j,i);
if(ans == -1) continue;
dp[i] = min(dp[i],dp[j - 1] + (i - j + 1) * ans + K);
}
}
put(dp[T]);
}
int main(){
// file();
readdata();
work();
return 0;
}
标签:ch,const,NOIP,int,void,20190813,2018,putch,dp 来源: https://blog.csdn.net/weixin_44584560/article/details/99477611