【zzulioj】河南多校训练(985专场)<位运算--DP---思维--扩展欧几里德---回溯---字典树---状态优化>
来源:互联网 发布:《算法时代》 编辑:程序博客网 时间:2024/05/17 08:36
Problem B: 985的数学难题
Time Limit: 2 Sec Memory Limit: 128 MBSubmit: 85 Solved: 13
SubmitStatusWeb Board
Description
985有n个正整数,他想快速知道下面函数的返回值
int a[N+1];
long long Solve() {
int i, j;
long long ans = 0;
for(i = 1; i <= N; i++) {
for(int j = i + 1; j <= N; j++) {
ans += a[i] + a[j] + (a[i] ^ a[j]) + (a[i] | a[j]) + (a[i] & a[j]);
}
}
return ans;
}
注:^表示异或运算。
Input
第一行输入一个整数t,代表有t组测试数据。
每组数据第一行输入一个整数代表元素个数,接下来一行输入n个正整数a[]。
注:1 <= t <= 30,1 <= n,a[] <= 100000。
Output
一个整数代表最后的返回值ans。
Sample Input
2
1
10
2
1 1
Sample Output
0
4
HINT
两个数的&运算+两个数的^运算=两个数的|运算--
先求各数之和--然后求位运算的值:
位运算的求法可以分位求--
从数大到小--(这样位数不会减少)
每位分为0和1--计算与后面数的位运算
代码:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define LL long longLL n,s,shu[100100],ge[32];LL ssss[32];void ss(int xx){ int lp=0; while (xx) { if (xx%2) ge[lp]++; lp++; xx/=2; }}bool cmp(int xx,int yy){ return xx>yy;}void sl(int xx,int pp){ int lp=0; while (xx) { if (xx%2) { ge[lp]--; s+=pp*ssss[lp]*2;//|| } else { s+=ge[lp]*ssss[lp]*2;//|| } xx/=2; lp++; }}int main(){ // |=&+^;====2*a|b ssss[0]=1; for (int i=1;i<30;i++) ssss[i]=ssss[i-1]*2; int t;scanf("%d",&t); while (t--) { scanf("%d",&n);s=0; for (int i=0;i<n;i++) { scanf("%d",&shu[i]); s+=(n-1)*shu[i]; } //转化为2个2个的| 运算--- sort(shu,shu+n,cmp); memset(ge,0,sizeof(ge)); for (int i=0;i<n;i++) ss(shu[i]); int op=1; for (int i=0;i<n-1;i++ ) { // printf("%d 66\n",shu[i]); sl(shu[i],n-1-i); } printf("%lld\n",s); } return 0;}/************************************************************** Problem: 1893 User: Leibniz_Zhang Language: C++ Result: Accepted Time:942 ms Memory:1660 kb****************************************************************/
Problem C: 985的方格难题
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 330 Solved: 62
SubmitStatusWeb Board
Description
985走入了一个n * n的方格地图,他已经知道其中有一个格子是坏的。现在他要从(1, 1)走到(n, n),每次只可以向下或者向右走一步,问他能否到达(n,n)。若不能到达输出-1,反之输出到达(n,n)的方案数。
Input
第一行输入一个整数t,代表有t组测试数据。
每组数据第一行输入三个整数n,x,y,分别代表方格地图的大小以及坏掉格子的位置。
注:1 <= t <= 20,1 <= n <= 30,1 <= x,y <= n。
Output
若可以到达(n,n)则输出方案数对1e9 + 7取余的结果,反之输出-1。
Sample Input
2
2 1 2
2 2 2
Sample Output
1
-1
HINT
简单DP--找到动态方程: ma[i][j]=ma[i-1][j]+ma[i][j-1];
不要忘了取余---因为这个我wrong了几次----尴尬
代码:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define LL long longLL ma[50][50];int main() { int t;scanf("%d",&t); while (t--) { int n,x,y; scanf("%d%d%d",&n,&x,&y); memset(ma,0,sizeof(ma)); for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) { if (i==x&&j==y) ma[i][j]=0; else if (i==1&&j==1) ma[i][j]=1; else ma[i][j]=ma[i-1][j]+ma[i][j-1]; } } if (ma[n][n]) { ma[n][n]=ma[n][n]%1000000007; printf("%lld\n",ma[n][n]); } else printf("-1\n"); } return 0;}/************************************************************** Problem: 1894 User: Leibniz_Zhang Language: C++ Result: Accepted Time:0 ms Memory:892 kb****************************************************************/
Problem D: 985的0-1串难题
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 111 Solved: 19
SubmitStatusWeb Board
Description
985有一个长度为n的0-1串,已知他最多可以修改k次(每次修改一个字符即0->1 或者 1->0),他想知道连续的全1子串最长是多少。
Input
第一行输入一个整数t,代表有t组测试数据。
每组数据第一行输入两个整数n,k分别代笔上面的信息。
注:1 <= t <= 12,1 <= n <= 100000,0 <= k <= 100000。
Output
一个整数代表可以得到的最大长度。
Sample Input
2
6 3
010100
6 2
010100
Sample Output
5
4
HINT
记录一下0的位置--
如果o的个数小于等于k直接输出n
否则求第i个0到第i+k+1个0之间的数--(他们之间有k个0---)
记得在最开始和结束的位置加上两个0---便于计算最前和最后k个0的情况--
代码:
#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;#define LL long longint shu[100100];int he[100100];int main() { int t;scanf("%d",&t); while (t--) { char ch[100100]; int n,k,kp; scanf("%d%d",&n,&k); scanf("%s",ch); kp=0; shu[kp++]=0; for (int i=0;i<n;i++) if (ch[i]=='0') shu[kp++]=i+1; if (kp-1<=k) printf("%d\n",n); else { int mi=-1; shu[kp++]=n+1; for (int i=k+1;i<kp;i++) { // printf("%d %d %d %d\n",i,i-k-1,shu[i],shu[i-k-1]); mi=max(shu[i]-shu[i-k-1]-1,mi); } printf("%d\n",mi); } } return 0;}/************************************************************** Problem: 1895 User: Leibniz_Zhang Language: C++ Result: Accepted Time:13 ms Memory:1676 kb****************************************************************/
Problem E: 985的买饮料难题
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 226 Solved: 119
SubmitStatusWeb Board
Description
天气太热了,985制定了对未来的规划即第i天喝a[i]瓶饮料。为了节约开支,他打听到了第i天每瓶饮料的价格p[i]。
为了不让自己的规划落空,他想知道这n天他至少要花多少钱。
精明的985可以选择在任意一天买数目不限的饮料,而且他有一个神奇的冰箱,可以将提前购买的饮料保存下来(至少在这n天里是可以饮用的)。
Input
第一行输入一个整数t,代表有t组测试数据。
每组数据第一行输入一个整数n代表规划的总天数,接下来有n行,每行输入两个整数a[],p[]分别代表上面提到的信息。
注:1 <= t <= 30,1 <= n <= 1000,1 <= a[],p[] <= 100。
Output
输出一个整数代表最后的结果。
Sample Input
2
2
25 56
94 17
5
39 21
95 89
73 90
9 55
85 32
Sample Output
2998
6321
HINT
记录一下最小单价就行了---(签到题)
代码:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define LL long longint main() { int t;scanf("%d",&t); while (t--) { int n;scanf("%d",&n); int mi=9999,s=0; int a,b; for (int i=0;i<n;i++) { scanf("%d%d",&a,&b); mi=min(b,mi); s+=a*mi; } printf("%d\n",s); } return 0;}/************************************************************** Problem: 1896 User: Leibniz_Zhang Language: C++ Result: Accepted Time:7 ms Memory:872 kb****************************************************************/
Problem F: 985的红绿灯难题
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 205 Solved: 126
SubmitStatusWeb Board
Description
已知红、绿、黄灯各持续r、g、y秒,985发现此时灯刚刚变绿,他想知道x秒后灯是什么颜色。
Input
第一行输入一个整数t,代表有t组测试数据。
每组数据输入四个整数x,g,y,r。
注:1 <= t <= 30,1 <= x,g,r,y <= 1e9。
Output
若x秒后变成红色输出R,变成绿色输出G,反之输出Y。
Sample Input
3
5 5 2 8
7 5 2 8
16 5 2 8
Sample Output
Y
R
G
HINT
红绿灯顺序:绿->黄->红->绿-------(签到题)
代码:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define LL long longint main() { int t;scanf("%d",&t); while (t--) { LL x,g,y,r,s; scanf("%lld%lld%lld%lld",&x,&g,&y,&r); s=g+y+r; x%=s; if (x<g) printf("G\n"); else if (x<g+y) printf("Y\n"); else printf("R\n"); } return 0;}/************************************************************** Problem: 1897 User: Leibniz_Zhang Language: C++ Result: Accepted Time:0 ms Memory:872 kb****************************************************************/
Problem G: 985的数字难题
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 256 Solved: 85
SubmitStatusWeb Board
Description
985有n个数,已知每次操作可以将其中不相同的两个数一个加一、一个减一,操作次数不限。
问他最多可以得到多少个相同的数。
Input
第一行输入一个整数t,代表有t组测试数据。
每组数据占两行,第一行输入一个n代表元素个数,下面一行输入n个整数a[]。
注:1 <= t <= 30,1 <= n <= 1e4,1 <= a[] <= 1e3。
Output
输出一个整数代表最多可以得到多少个相同的数。
Sample Input
2
3
1 1 1
2
2 3
Sample Output
3
1
HINT
题解:
如果n个数之和是n的倍数--那么一定可以变成n个相同的数--
如果不能---(贪心)可以让一个数取极值--那么剩下的n-1个数就能变成相同的--
代码:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define LL long longint shu[42000],n;int main() { int t,s;scanf("%d",&t); while (t--) { scanf("%d",&n);s=0; for (int i=0;i<n;i++) { scanf("%d",&shu[i]); s+=shu[i]; } if (s%n==0) printf("%d\n",n); else printf("%d\n",n-1); } return 0;}/************************************************************** Problem: 1898 User: Leibniz_Zhang Language: C++ Result: Accepted Time:19 ms Memory:1036 kb****************************************************************/
Problem H: 985的最大和难题
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 216 Solved: 11
SubmitStatusWeb Board
Description
985有2 * n - 1个整数,他每次可以将其中n个数变号,操作次数不限,问他可以得到的最大和。
Input
第一行输入一个整数t,代表有t组测试数据。
每组数据占两行,第一行输入一个整数n,下面一行输入2*n-1个整数a[]。
注:1 <= t <= 32,1 <= n <= 1e3,-1e3 <= a[] <= 1e3。
Output
输出一个整数代表可以得到的最大和。
Sample Input
2
2
1 1 1
2
-10 20 -10
Sample Output
340
HINT
设负数的个数为p,交换的次数为y,全体都变有x次
可列出:
扩展欧几里德:
x(2n-1)+ y*n=1
进而得:
X*P*(2N-1)+Y*P*N=P
1》如果x*p为偶数--说明都换位了非负数==只需求所有数的绝对值之和
2》如果x*p为奇数--就是x, p都为奇数的情况下--
p个负数变成了正数,,但是所有的正数都又i经过x*p次换号--都变为了非正数--
在这种情况下我们只能的到这个方程:
(X*P-1)*(2N-1)+(Y*P-1)*N=P-1
或这个方程:(X*P+1)*(2N-1)+(Y*P+1)*N=P+1
这样就只有一个是非整数---
我们就求出所有数的绝对值之和减去2*最小的绝对值(让它为非正数)
代码:
#include<cstdio>#include<cstring>#include<string>#include<algorithm>using namespace std;#define LL long longint extend(int a,int b,int &x,int &y){ if (b==0) { x=1;y=0; return a; } else{ int t=extend(b,a%b,y,x); y-=(a/b*x); return t; }}int shu[1020];int main(){ int t;scanf("%d",&t); while (t--) { int n;scanf("%d",&n); int s=0,a,p=2*n-1,zheng,fu=0; for (int i=0;i<p;i++) { scanf("%d",&shu[i]); if (shu[i]<0) fu++; } int x,y; extend(p,n,x,y); x=(x%n+n)%n; if (fu%2&&x%2) { int mi=100000; for (int i=0;i<p;i++) { shu[i]=abs(shu[i]); s+=shu[i]; } sort(shu,shu+p); s-=shu[0]*2; } else { for (int i=0;i<p;i++) s+=abs(shu[i]); } printf("%d\n",s); } return 0;} /************************************************************** Problem: 1899 User: Leibniz_Zhang Language: C++ Result: Accepted Time:1 ms Memory:880 kb****************************************************************/
Problem I: 985的“树”难题
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 24 Solved: 4
SubmitStatusWeb Board
Description
985给你一棵“树”以及它的根节点,要求你先判定它是否是一棵树,其次他想知道每个节点的“太子”数目以及它的父亲(root的话输出自己)。
“太子判定条件”:
一、若x是y的孩子节点,那么x是y的“太子”;
二、若x是y的“太子”且y是z的“太子”,那么x是z的“太子”。
Input
第一行输入一个整数t,代表有t组测试数据。
每组数据第一行输入两个整数n,root分别代表树的节点数目以及根节点的编号。
接下来n-1行,每行输出两个整数u,v代表u节点和v节点之间有一条树边。
注:1 <= t <= 20,1 <= n <= 1e4,1 <= root <= n,1 <= u,v <= n。
Output
对每一组数据,若给定的“树”不合法输出NO即可,反之输出YES,接下来输出占两行:
第一行输出n个整数代表每个节点的“太子”数目,
第二行输出n个整数代表每个节点的父亲节点编号。
输出顺序从1到n,每两个数之间有一个空格,最后一个数后面没有空格。
Sample Input
23 11 22 32 11 1
Sample Output
YES2 1 01 1 2NO
HINT
比赛的时候看成了求父亲节点的数目---然后memset(fafe,true,sizeof(fafe));这个地方还写成了memset(fafe,true,sizeof(boot));
回溯法求子节点的数目----LCA中的原理--
wrong的好伤心呀---
代码:
#include<cstdio>#include<cstring>#include<string>#include<algorithm>using namespace std;#define LL long long#define MA 40000struct node{int to,next;}bian[MA];int head[MA];bool fafe[MA];void DFS(int xx){int lp;for (int j=head[xx];j!=-1;j=bian[j].next){lp=bian[j].to;if (fafe[lp]){fafe[lp]=false;DFS(lp);}}}int vis[MA*100];int D[MA],kp;int ans[MA],wei[MA],ii,fer[MA];void xun(int xx,int de){D[xx]=de;vis[kp++]=xx;for (int j=head[xx];j!=-1;j=bian[j].next){int lp=bian[j].to;if (fafe[lp]) { fafe[lp]=false; fer[lp]=xx; xun(lp,de+1); vis[kp++]=xx; }}return ;}int main(){int t;scanf("%d",&t);while (t--){int n,boot;scanf("%d%d",&n,&boot);for (int i=1;i<=n;i++)head[i]=-1;int a,b;for (int i=0;i<n-1;i++){scanf("%d%d",&a,&b);bian[2*i].to=a;bian[i*2].next=head[b];head[b]=2*i;bian[2*i+1].to=b;bian[i*2+1].next=head[a];head[a]=2*i+1;}memset(fafe,true,sizeof(fafe));fafe[boot]=false;DFS(boot);bool falg=true;for (int i=1;i<=n;i++){if (fafe[i]){falg=false;break;}}if (!falg){printf("NO\n");continue;}memset(D,0,sizeof(D));kp=1;memset(fafe,true,sizeof(fafe));fafe[boot]=false;xun(boot,1);//错误了--memset(ans,0,sizeof(ans));memset(wei,0,sizeof(wei));for (int i=1;i<kp;i++){ii=vis[i];if (!wei[ii])wei[ii]=i;else{ans[ii]+=i-wei[ii];wei[ii]=i;}}for (int i=1;i<=n;i++)ans[i]/=2;printf("YES\n");for (int i=1;i<n;i++)printf("%d ",ans[i]);printf("%d\n",ans[n]);for (int i=1;i<=n;i++)D[i]--;D[boot]=1;fer[boot]=boot;for (int i=1;i<n;i++)printf("%d ",fer[i]);printf("%d\n",fer[n]);}return 0;}
Problem J: 985的SS串难题
Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 37 Solved: 4
SubmitStatusWeb Board
Description
985定义一个串是SS串的条件是:串中不同字符个数为平方数或者平方数的2倍。现在他给你一个字符串,要求你按字典序输出所有不相同的SS子串。
(1 4 9 16 25 36...)
(2 8 18 32 50 72...)
Input
第一行输入一个整数t,代表有t组测试数据。每组数据输入一个字符串str。
注:1 <= t <= 10,1 <= |str| <= 1000,保证str里面只有小写字母。
Output
按字典序输出所有不相同的SS串。
Sample Input
1
abc
Sample Output
a
ab
b
bc
c
HINT
字典树水过(比赛时内存释放应该是出了一些情况---所以我开了12个boot(字典树的根))
然后就是存入单词--输出单词---
用字典树输出字典序好完美-.-
代码:
#include<cstdio>#include<string>#include<vector>#include<cstring>#include<algorithm>using namespace std;#define LL long longbool fafe[26];int dui[10]={1,4,9,16,25,2,8,18};int sl(int xx){ for (int i=0;i<8;i++) if (xx==dui[i]) return true; return false;}struct node{ struct node * chi[26]; char cha[1050]; int fafa;}boot[12];//struct node *boot[12] = new node();void jia(char xx[],int lp){ node * kk=&boot[lp]; int ll=strlen(xx),k; for (int i=0;i<ll;i++) { k=xx[i]-'a'; if (!kk->chi[k]) kk->chi[k]=new node(); kk=kk->chi[k]; } strcpy(kk->cha,xx); kk->fafa=1;}void prin(node * xx){ if (xx->fafa) printf("%s\n",xx->cha); for (int i=0;i<26;i++) { if (xx->chi[i]) prin(xx->chi[i]); }}void booop(node * xx){ for (int i=0;i<26;i++) if (xx->chi[i]) booop(xx->chi[i]); delete xx;}int main(){ int t,s,kp;scanf("%d",&t); char ch[1050],pp[1050]; int ca=0; while (t--) { scanf("%s",ch); int n=strlen(ch);//printf("%d 66\n",n); for (int i=0;i<n;i++) { memset(fafe,false,sizeof(fafe)); s=0; for (int j=i;j<n;j++) { int p=ch[j]-'a'; if (!fafe[p]) { fafe[p]=true; s++; } if (sl(s)) { kp=0; for (int k=i;k<=j;k++) pp[kp++]=ch[k]; pp[kp]=0; jia(pp,ca); } } } for (int i=0;i<26;i++) { if (boot[ca].chi[i]) prin(boot[ca].chi[i]); } for (int i=0;i<26;i++) { if (boot[ca].chi[i]) booop(boot[ca].chi[i]); } ca++; } return 0;} /************************************************************** Problem: 1901 User: Leibniz_Zhang Language: C++ Result: Accepted Time:837 ms Memory:88400 kb****************************************************************/
Problem K: 985的因子对难题
Time Limit: 2 Sec Memory Limit: 128 MBSubmit: 114 Solved: 22
SubmitStatusWeb Board
Description
985有n个正整数,他想知道存在多少个不同的因子对(a[i], a[j])使得
1 <= i, j <= n && i != j && a[j] % a[i] == 0,其中i和j是元素的下标。
特别地,他认为(a[i],a[j])与(a[j],a[i])是一样的因子对。
Input
第一行输入一个整数t,代表有t组测试数据。
每组数据占两行,第一行输入一个n代表元素个数,下面一行输入n个整数a[]。
注:1 <= t <= 30,1 <= n <= 1e5,1 <= a[] <= 1e6。
Output
一个整数代表最后的答案。
Sample Input
2
5
1 2 3 4 5
5
2 2 2 2 2
Sample Output
5
10
HINT
优化:相同数合并--再用类似素数打表的O(nlogn)的计算思路--挤了过去
代码:
#include<cstdio>#include<cstring>#include<string>#include<algorithm>using namespace std;#define LL long longint n,shu[1001000],pp[1001000];int main() { int t;scanf("%d",&t); while (t--) { scanf("%d",&n);int a; memset(shu,0,sizeof(shu)); memset(pp,0,sizeof(pp)); for (int i=0;i<n;i++) { scanf("%d",&a); shu[a]++; } for (int i=1;i<=1000000;i++) { if (shu[i]) { for (int j=2*i;j<=1000000;j+=i) pp[j]+=shu[i]; } } LL s=0; for (int i=1;i<=1000000;i++) { if (shu[i]) { // printf("%d %d %d 66\n",i,shu[i],pp[i]); if (shu[i]>1) s+=(shu[i]*(shu[i]-1))/2; s+=pp[i]*shu[i]; // printf("%lld\n",s); } } printf("%lld\n",s); } return 0;}/************************************************************** Problem: 1902 User: Leibniz_Zhang Language: C++ Result: Accepted Time:1252 ms Memory:8692 kb****************************************************************/
X*P*(2N-1)+Y*P*N=P
0 0
- 【zzulioj】河南多校训练(985专场)<位运算--DP---思维--扩展欧几里德---回溯---字典树---状态优化>
- zzulioj 多校训练2(小火山专场)
- Contest - 多校训练(985专场)
- Contest - 多校训练(985专场)
- ZZULI 多校训练(985专场)
- 【多校训练】ZZULIOJ 1893 985的数学难题【位运算】
- ZZULIOJ 多校训练三
- 【多校训练】ZZULIOJ 1894 985的方格难题
- 【多校训练】ZZULIOJ 1898 985的数字难题
- 【多校训练】ZZULIOJ 1896 985的买饮料难题
- 【多校训练】ZZUliOJ 1902 985的因子对难题
- 【Zzulioj 1919】多校训练三(二分->最大值最小化)
- 【南阳1291】河南多校训练
- 【南阳1261】河南多校训练
- 2017多校训练赛第四场 HDU 6078 Wavel Sequence(dp+优化)
- 【多校训练】ZZULIOJ 1895 985的0-1串难题
- 【ZzuliOJ 1918】多校训练三 G (二分图最大匹配模板题)
- 【多校训练】ZZULIOJ 1908 小火山的围棋梦想
- Unity3d LOD 使用以及 Bias精度设置
- android开发中几个常见的错误及解决方法
- 背包问题
- jquery表单序列化
- RecyclerView下拉刷新与上拉更多
- 【zzulioj】河南多校训练(985专场)<位运算--DP---思维--扩展欧几里德---回溯---字典树---状态优化>
- 利用wsdl生成webservice client
- java中的session
- make版本替换
- jsp&Servlet-单表信息操作
- python2和python3的区别
- ZZULI OJ 1896: 985的买饮料难题
- Redis之—— java客户端链接不上redis解决方案
- linux高级编程四shell编程/指针