考试 —— NOI2016 山东省队选拔第一轮 Day 1

来源:互联网 发布:矢量图软件哪个好 编辑:程序博客网 时间:2024/05/01 12:43

NOI2016 山东省队选拔第一轮 Day 1


被虐得好爽。


这里写图片描述


T1 储能表


【问题描述】

有一个 n 行m 列的表格,行从 0n1 编号,列从 0m1 编号。
每个格子都储存着能量。最初,第 i 行第 j 列的格子储存着(i xor j)点能量。
所以,整个表格储存的总能量是,

这里写图片描述

随着时间的推移,格子中的能量会渐渐减少。
一个时间单位,每个格子中的能量会减少 1
显然,一个格子的能量减少到 0 之后就不会再减少了。
也就是说,k 个时间单位后,整个表格储存的总能量是,

这里写图片描述

给出一个表格,求 k 个时间单位后它储存的总能量。
由于总能量可能较大,输出时对 p 取模。


【输入格式】

第一行一个整数 T,表示数据组数。
接下来 T 行,每行四个整数 nmkp


【输出格式】

T 行,每行一个数,表示总能量对 p 取模后的结果。


【样例输入】

3
2 2 0 100
3 3 0 100
3 3 1 100


【样例输出】

2
12
6


【数据规模和约定】

这里写图片描述


【想法】

这个题目我开始是想找规律,然后确实发现了一些“规律”,结果敲了半个小时发现错了,改进“规律”后又敲了半个小时,结果发现又错了,然后又改进………

然后,然后就没有然后了。
当我幡然醒悟,考试就结束了QWQ

据说题目正解是 “shuwei” DP,反正我是不懂。


T2 数字配对


【问题描述】

n 种数字,第 i 种数字是 ai 、有 bi 个,权值是 ci
若两个数字 aiaj 满足, aiaj 的倍数,且 aiaj 是一个质数,那么这两个数字可以配对,并获得 cicj 的价值。
一个数字只能参与一次配对,可以不参与配对。
在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。


【输入格式】

第一行一个整数 n
第二行 n 个整数 a1a2 、……、an
第三行 n 个整数 b1b2 、……、bn
第四行 n 个整数 c1c2 、……、cn


【输出格式】

一行一个数,最多进行多少次配对。


【样例输入】

3
2 4 8
2 200 7
-1 -2 1


【样例输出】

4

【数据规模和约定】

这里写图片描述


【Solution】

在考场上根本就没有想,只是最开始阅读所有题目时扫了一眼,之后就再也没有看过了。
当时就感觉这道题有二分图的味道,配对是吧,那不就是连边吗???

我们将所有满足条件的几对不同种类的数连起来,然后从源点向这对数的一边连一条容量为 bi,费用为 0 的边,从这对数的另一边向汇点连一条容量为 bj,费用为 0 的边,然后将它们之间连一条容量为 +,费用为 cicj 的边。

然后不断地找最小费用增广路。
每次增广,我们付出的都是最小的代价。
所以,当 当前最小费用 大于 0 时,我们就可以知道,当前的最大流就为所求解。
注意,最后一次增广时的流量也要计算进去啊(找到能使 当前最小费用 小于等于 0 的最大的流量),具体实现请见代码。

问题又来了,那我们怎么判断从一对数的哪一边连到汇点和源点呢??
根据唯一分解定理,

ai=Pd11Pd22Pd33......PdlldkN
aj=Pe11Pe22Pe33PeqqekN

所以,若 ai0(mod aj)aiaj 为质数,那么有且只有一个 kN,使得 dk=ek+1dm=emmkl=q

综上,k=1pdk=k=1qek+1,所以 aiaj 的质因子个数必定一奇一偶,所以我们可以按照质因子个数的奇偶性将一对数对给分成两边。

问题得解。


【Code】

[cpp]
  1. #include <iostream>  
  2. #include <cstdio>  
  3. #include <cstring>  
  4. #include <queue>  
  5. #include <cmath>  
  6.   
  7. #define LL long long  
  8.   
  9. #define ANOTHER 200  
  10. #define Min(x,y) ((x)<(y)?(x):(y))  
  11. #define INF 0x3f3f3f3f  
  12. #define ss 0  
  13. #define tt 500  
  14.   
  15. using namespace std;  
  16.   
  17. LL n,Minx,ans,cnt,tot,Max_flow,sum;  
  18. bool flag;  
  19. bool lefts[1000];  
  20. LL a[1000],b[1000],c[1000];  
  21. LL nxt[100100],head[510];  
  22. LL data[100100],wei[100100],flow[100100];  
  23. LL f[300][300];  
  24. LL dis[510],pre[510];  
  25. bool in_stack[510];  
  26. queue<LL>q;  
  27.   
  28. void add(LL x,LL y,LL a,LL b){  
  29.     nxt[cnt]=head[x];data[cnt]=y;wei[cnt]=b;flow[cnt]=a;head[x]=cnt++;  
  30.     nxt[cnt]=head[y];data[cnt]=x;wei[cnt]=-b;flow[cnt]=0;head[y]=cnt++;  
  31. }  
  32.   
  33. bool BFS(){      
  34.     memset(dis,0x3f,sizeof dis);dis[ss]=0;in_stack[ss]=true;q.push(ss);pre[ss]=pre[tt]=-1;      
  35.     while(!q.empty()){      
  36.         LL now=q.front();      
  37.         q.pop();      
  38.         in_stack[now]=false;      
  39.         for(LL i=head[now];i!=-1;i=nxt[i]){      
  40.             if(flow[i]!=0&&dis[data[i]]>dis[now]+wei[i]){      
  41.                 dis[data[i]]=dis[now]+wei[i];      
  42.                 pre[data[i]]=i^1;      
  43.                 if(!in_stack[data[i]]){      
  44.                     in_stack[data[i]]=true;      
  45.                     q.push(data[i]);      
  46.                 }      
  47.             }      
  48.         }      
  49.     }      
  50.     return pre[tt]!=-1;      
  51. }      
  52.       
  53. bool dfs(){  
  54.       
  55.     LL Low=INF;      
  56.       
  57.     for(LL i=pre[tt];i!=-1;i=pre[data[i]])Low=Min(Low,flow[i^1]);      
  58.     for(LL i=pre[tt];i!=-1;i=pre[data[i]])flow[i^1]-=Low,flow[i]+=Low;       
  59.       
  60.     LL tmp=ans;  
  61.       
  62.     ans+=Low*dis[tt];  
  63.           
  64.     if(ans>0){  
  65.         printf(”%I64d\n”,(0-tmp)/dis[tt]+Max_flow);  
  66.         flag=true;  
  67.         return false;  
  68.     }  
  69.     Max_flow+=Low;  
  70.     return true;  
  71. }  
  72.   
  73. bool is_prime(LL x){  
  74.     LL px=(LL)sqrt((double)x);  
  75.     for(LL i=2;i<=px;i++)if(!(x%i))return false;  
  76.     return true;  
  77. }  
  78.   
  79. int main(){  
  80.       
  81.     freopen(”pair.in”,“r”,stdin);  
  82.     freopen(”pair.out”,“w”,stdout);  
  83.       
  84.     memset(head,-1,sizeof head);  
  85.       
  86.     scanf(”%I64d”,&n);  
  87.     for(LL i=1;i<=n;i++)scanf(“%I64d”,&a[i]);  
  88.     for(LL i=1;i<=n;i++){  
  89.         scanf(”%I64d”,&b[i]);  
  90.         sum+=b[i];  
  91.     }  
  92.     for(LL i=1;i<=n;i++)scanf(“%I64d”,&c[i]);  
  93.       
  94.     for(LL i=1;i<=n;i++){  
  95.         LL tmp=a[i];  
  96.         LL tot=0;  
  97.         for(LL j=2;j<=tmp;j++){  
  98.             if(tmp%j==0){  
  99.                 while(tmp%j==0){  
  100.                     tmp/=j;  
  101.                     tot++;  
  102.                 }  
  103.             }  
  104.         }  
  105.         if((tot&1))   
  106.             lefts[i]=true;  
  107.     }  
  108.       
  109.     for(LL i=1;i<=n;i++){  
  110.         for(LL j=i+1;j<=n;j++)  
  111.             if((a[i]%a[j]==0&&is_prime(a[i]/a[j]))||(a[j]%a[i]==0&&is_prime(a[j]/a[i]))){  
  112.                 if(lefts[i])  
  113.                     add(i,j,INF,-c[i]*c[j]);  
  114.                 else  
  115.                     add(j,i,INF,-c[i]*c[j]);  
  116.             }  
  117.     }  
  118.               
  119.     for(LL i=1;i<=n;i++){  
  120.         if(lefts[i])  
  121.             add(ss,i,b[i],0);  
  122.         else  
  123.             add(i,tt,b[i],0);   
  124.     }  
  125.     while(BFS())if(!dfs())break;  
  126.     if(!flag)printf(“%I64d\n”,Max_flow);  
  127.       
  128.     return 0;  
  129. }  

T3 游戏


【问题描述】

Alice 和 Bob 在玩一个游戏。
游戏在一棵有 n 个点的树上进行。
最初,每个点上都只有一个数字,那个数字是 123456789123456789。
有时,Alice 会选择一条从 st 的路径,在这条路径上的每一个点上都添加一个数字。
对于路径上的一个点 r,若 rs 的距离是dis,那么 Alice 在点 r 上添加的数字是adis+b
有时,Bob 会选择一条从 st 的路径。
他需要先从这条路径上选择一个点,再从那个点上选择一个数字。
Bob 选择的数字越小越好,但大量的数字让Bob 眼花缭乱。
Bob 需要你帮他找出他能够选择的最小的数字。


【输入格式】

第一行两个数字 nm,表示树的点数和进行的操作数。
接下来 n1 行,每行三个数字 uvw,表示树上有一条连接 uv 的边,长度是 w
接下来 m 行,每行第一个数是 12
若第一个数是 1,表示 Alice 进行操作,接下来四个数字 stab
若第一个数是 2,表示 Bob 进行操作,接下来两个数字 st


【输出格式】

每当 Bob 进行操作,输出一行一个数,表示他能够选择的最小的数字。


【样例输入】

3 5
1 2 10
2 3 20
2 1 3
1 2 3 5 6
2 2 3
1 2 3 -5 -6
2 2 3


【样例输出】

123456789123456789
6
-106


【数据规模和约定】

这里写图片描述


【想法】

据说是搜索?

1 0
原创粉丝点击