对了昨天笔记忘记写了,我robocom进国赛了...省赛进国赛的最后几名,我这运气也太好了。哭死...
今天打了场div2,还做了2题就没有了.....感觉自己的效率真的需要提升了...
要注重效率啊,不要太关心时间,要达到忘我的境界,但事实上做不到....
还有今天牛客我换了个头像,改了个名字,确实好开心啊。
1个小时之后还要打div4,闲话少说吧。
CF882:
A:
思路还是很简单的,自己手玩一下样例就知道怎么做了,即删除n-k个最大的区间即可
B:这题我想了好久,我是真的菜啊....
其实就是没考虑&的性质。a&b<=a+b,这是一定成立的!
所以我们从前到后&,如果&到0就区间就答案就++,新开一个区间。
如果最后我们统计的区间个数为0的话,我们输出1即可(a&b<=a+b)!!
#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<map>
#include<set>
#include <utility>
#include <list>
using namespace std;
typedef long long ll ;
typedef unsigned long long ull ;
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;//106110956
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){
if (ch == '-')
f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = (x<<1) + (x<<3) + (ch^48);
ch = getchar();
}
return x * f;
}
void print(__int128 num) {
if(num) {
print(num/10);
putchar(num%10+'0');
}
}
ll ex_gcd(ll a,ll b,ll& x,ll& y){
if(b==0){
x=1;
y=0;
return a;
}
ll d=ex_gcd(b,a%b,y,x);
y=y-a/b*x;
return d;
}
int t;
int n;
int main(){
scanf("%d",&t);
while(t--){
int ans;
int cnt=0;
int flag=0;
ll x;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&x);
if(flag==0){
ans=x;
flag=1;
if(ans==0){
flag=0;
cnt++;
}
}else{
ans=ans&x;
if(ans==0){
cnt++;
flag=0;
}
}
}
if(ans==0){
printf("%d\n",cnt);
}else{
if(cnt==0){
printf("1\n");
}else{
printf("%d\n",cnt);
}
}
}
return 0;
}
C:这题考察异或..我还真没有啥思路...样例都没看出来怎么出现的
然后去补题了..
我们发现后缀数组对答案没有影响,
假设数组为 1 2 3 4 5 6,假设1和2异或为我们的答案,这时我们可以构造1 2 3 4 5 6 (3^4^5^6)
(3^4^5^6)和3.4.5.6异或为0,0异或任何数都为0
所以这题可以转换为求最大的一段异或和
我们发现数组的范围为2^8,所以异或的最大值为2^8,因为异或是按位异或的(最大的可能也才是8个1相连)即256
我们设dp[i][j]为第i个数的j状态,dp[i][j]=max(dp[i][j],dp[i-1][j^a[i]])因为我们是从前往后异或的,并且j^a[i]^a[i]=j
i的范围为1到n,因为后面也是等价的!!,仔细想想是一样的。
j的范围为0到256
#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<map>
#include<set>
#include <utility>
#include <list>
using namespace std;
typedef long long ll ;
typedef unsigned long long ull ;
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;//106110956
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){
if (ch == '-')
f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = (x<<1) + (x<<3) + (ch^48);
ch = getchar();
}
return x * f;
}
void print(__int128 num) {
if(num) {
print(num/10);
putchar(num%10+'0');
}
}
ll ex_gcd(ll a,ll b,ll& x,ll& y){
if(b==0){
x=1;
y=0;
return a;
}
ll d=ex_gcd(b,a%b,y,x);
y=y-a/b*x;
return d;
}
int t;
int n;
int dp[100005][260];
int a[100005];
int main(){
scanf("%d",&t);
while(t--){
int ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
ans=max(ans,a[i]);
for(int j=0;j<256;j++){
dp[i][j]=0;
}
dp[i][a[i]]=1;
}
for(int i=1;i<=n;i++){
for(int j=0;j<256;j++){
dp[i][j]=max(dp[i][j],dp[i-1][j^a[i]]);
if(dp[i][j]==1){
ans=max(ans,j);
}
}
}
printf("%d\n",ans);
}
return 0;
}
最近洛谷题单刷到了图的基本应用了,前面后刷了刷并查集,主要是扩展域并查集,真的好简单...比带权的好多了
P1621 集合
这题还是比较有意思的
首先打p到b之间的素数表,然后暴力即可...(我还用了欧拉筛法...)
然后我们枚举素数,然后找到第一个c满足: c*(素数)>=a,然后我们逐次增加c,如果(c+1)*(素数)<=b,我们就merge( c*(素数),(c+1)*(素数))即可
然后merge即可
然后学了存图...链式前向星,自我感觉还是比较简单的...(bushi)
P3916 图的遍历
这题挺有意思的...显示内存超了..我还找数组是不是开的太大了..
结果是dfs太多层的原因....
这题就是反向建边,从n到1循环
P1113 杂务
这题是动规.....
因为我们要做这件事情之前的所需要的时间一定在这件事情之前,对于事情i和它的需要的事情j
dp[i]=max(dp[i],dp[j]+a[i])
另外一种做法:拓扑排序
代码还是很好理解的
但是最好一开始入队列的时候的for循环放在while的外面
// deg是入度,在存图的时候需要录入数据
// A是排序后的数组
int deg[MAXN], A[MAXN];
bool toposort(int n)
{
int cnt = 0;
queue<int> q;
for (int i = 1; i <= n; ++i)
if (deg[i] == 0)
q.push(i);
while (!q.empty())
{
int t = q.front();
q.pop();
A[cnt++] = t;
for (auto to : edges[t])
{
deg[to]--;
if (deg[to] == 0) // 出现了新的入度为0的点
q.push(to);
}
}
return cnt == n;
}
还有:注意我们需要一个a数组来存储每一件事情的花费,不能直接用dp来存,否则就是它所有需要做的事情的总和了
dp[son[u][j]]=max(dp[son[u][j]],a[son[u][j]]+dp[u]);
P4017 最大食物链计数
这题我们需要开2个数组来统计出度和入度,入度为0的点即最佳生产者,出度为0的点为最佳消费者
状态转移方程
dp[son[u][j]]=(dp[son[u][j]]+dp[u])%mod;
P1807 最长路:
这一题感觉就比较难了....
我们要统计1到n的最长的路的距离
1的入度一定为0,但是还有其他点的入度为0
如果其他点不入队列,只有1入队列的话,那么他们延伸出来的点的入度永远大于 0
同理如果入队列的话,因为他们本身是无法到达的点,所以根本不可能会延伸到其他地方
所以我们需要单独处理其他入度为0的点....然后就很奇怪了...for循环必须在while外面,不然是不对的...不太懂.啊....
for(int i=2;i<=n;i++){
if(in[i]==0){
q.push(i);
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(int j=0;j<son[u].size();j++){
int k=son[u][j];
in[k]--;
if(in[k]==0){
q.push(k);
}
}
}
昨天打了场div4,直接拉跨了....排名7000多,对内大腿比我多了一题,排名3000多...
前几道题还是比较顺利的...然后D题..我没有太看懂题目的意思就开始做了....然后觉得这题好难....
不太会啊...然后又读了一边题意,然后明白了
D:
要使答案最小,我们只需求出最长的满足条件的序列,然后长度-序列的长度就是答案了,还是很好写的。。。但是因为数组少开了1倍,然后直接wa了2法...一开始我还以为读的太慢了,用了快速读,结果...
E:
这题的题意我感觉读了得10分钟,一直读不明白,然后在回去读题..一直往返..
最后好歹读明白了,
只要求满足(x1+w)^2+(x2+w)^2+...+(xn+w)^2==c的w即可
原来以为T组数据不算复杂度,最近听别人说算复杂度..昨天这场比赛就以为T算复杂度了...
事实上,T是不算复杂度的’
The sum of nn over all test cases doesn't exceed 2⋅10^5.
T不关系复杂度,但是n关系复杂度
另外这题我移项了,然后就是n*w^2+2*w(x1+x2+x3+..+xn)=c-(x1^2+x2^2...+xn^2)了
然后我们二分答案,但是出现了越界的现象..long long 越界...
然后我又开了double...结果也不行,浮点数二分很烦....一直调不对.....
是我浮点数二分写错了.....尴尬死了....
while(right-left>=1e-4){
double mid=(left+right)/2;
if(mid*mid*n+2*sum*mid>c){
right=mid;
}else{
left=mid;
}
}
正确思路:我们从1到n模拟计算即可..
如果出现了sum>c的情况就返回即可
a[i]范围为1e4,c的范围为1e18,所以我们的右边界为1e9即可
第一次mid=1e9/2,直接不行..
然后就逐渐缩小了..这个精度还是很烦人的
bool check(ll mid){
ll ans=0;
for(int i=1;i<=n;i++){
ans=ans+(a[i]+2*mid)*(a[i]+2*mid);
if(ans>c)return 0;
}
return 1;
}
F:
做完E题还有20分钟左右...感觉自己就做不出来...就没怎么思考了.
以为是gcd结果不是...
看我队友写的也挺麻烦的...
然后直接看榜一代码:真的6,思路很清晰
我们a[i]为一开始能跳i步的青蛙的个数,vis[j]就是在j设置陷阱能抓的青蛙的数量
如果x>n直接跳过即可
for(int i=1;i<=n;i++){
scanf("%lld",&x);
if(x>n)continue;
a[x]++;
}
然后我们枚举步数,在枚举位置
注意下面的双层循环的复杂度不为O(n^2)而是O(nln(n))调和级数
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j=j+i){
vis[j]=vis[j]+a[i];
ans=max(ans,vis[j]);
}
}
真的不太好想....
G: 我感觉这个G比F简单多了..
读懂题之后思路大体上就有了
如果罗盘在(x,y)如果使得罗盘不坏
即 有横坐标与x相同的点,有纵坐标与y相同的点,或者a-x/b-y=abs(1)
得x-y==a-b或者x+y==a+b,不存在两者同时成立的情况除非a,b和x,y重合
假设有k个互相满足上面情况答案为Ak2,不是Ck2
#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<map>
#include<set>
#include <utility>
#include <list>
using namespace std;
typedef long long ll ;
typedef unsigned long long ull ;
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;//106110956
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){
if (ch == '-')
f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = (x<<1) + (x<<3) + (ch^48);
ch = getchar();
}
return x * f;
}
void print(__int128 num) {
if(num) {
print(num/10);
putchar(num%10+'0');
}
}
ll ex_gcd(ll a,ll b,ll& x,ll& y){
if(b==0){
x=1;
y=0;
return a;
}
ll d=ex_gcd(b,a%b,y,x);
y=y-a/b*x;
return d;
}
int t;
int n;
map<ll,ll>mp1,mp2,mp3,mp4;
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
mp1.clear();
mp2.clear();
mp3.clear();
mp4.clear();
ll x,y;
ll ans=0;
for(int i=1;i<=n;i++){
scanf("%lld%lld",&x,&y);
mp1[x-y]++;
mp4[x+y]++;
mp2[x]++
mp3[y]++;
}
for(auto it=mp1.begin();it!=mp1.end();it++){
ans=ans+it->second*(it->second-1);
}
for(auto it=mp2.begin();it!=mp2.end();it++){
ans=ans+it->second*(it->second-1);
}
for(auto it=mp3.begin();it!=mp3.end();it++){
ans=ans+it->second*(it->second-1);
}
for(auto it=mp4.begin();it!=mp4.end();it++){
ans=ans+it->second*(it->second-1);
}
printf("%lld\n",ans);
}
return 0;
}
H:
这题也是比较简单的...
但就是题目难理解...带权并查集的模板题吧
#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<map>
#include<set>
#include <utility>
#include <list>
using namespace std;
typedef long long ll ;
typedef unsigned long long ull ;
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;//106110956
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){
if (ch == '-')
f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = (x<<1) + (x<<3) + (ch^48);
ch = getchar();
}
return x * f;
}
void print(__int128 num) {
if(num) {
print(num/10);
putchar(num%10+'0');
}
}
ll ex_gcd(ll a,ll b,ll& x,ll& y){
if(b==0){
x=1;
y=0;
return a;
}
ll d=ex_gcd(b,a%b,y,x);
y=y-a/b*x;
return d;
}
int t;
ll fa[200005];
ll ra[200005];
int n,m;
int find(int x){
if(x!=fa[x]){
int t=fa[x];
fa[x]=find(fa[x]);
ra[x]=ra[x]+ra[t];
}
return fa[x];
}
void merge(int x,int y,int w){
int fx=find(x);
int fy=find(y);
if(fx!=fy){
fa[fx]=fy;
ra[fx]=w+ra[y]-ra[x];
}
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
fa[i]=i;
ra[i]=0;
}
int x,y,z;
int flag=0;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
if(flag)continue;
int fx=find(x);
int fy=find(y);
if(fx!=fy){
merge(x,y,z);
}else{
if(ra[x]==ra[y]+z){
continue;
}else{
flag=1;
}
}
}
if(flag==0){
printf("YES\n");
}else{
printf("NO\n");
}
}
return 0;
}
P1983 [NOIP2013 普及组] 车站分级
又要开始拓扑排序了...
这题做的时候没思路...遂看标签,看完标签是拓扑排序,然后想了一会没思路....去看题解了
我们用vis[i][j]表示有一条从i到j的边
在m次读入中,我们用is数组来标记是否有没有读入,我们我们从a[i]到a[s]循环(因为起点和终点是在a[1]和a[s]之外的并且我们不知道起点和终点的坐标,所以我们不从1到n循环),s是这组一共有多少站点,如果没有标记,然后我们将其与我们读入的点建立有向边,如果有边就不用建边了..
我们设入度为0的点的深度为1,然后拓扑排序即可,我们求最大深度即可;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<map>
#include<set>
#include <utility>
#include <list>
using namespace std;
typedef long long ll ;
typedef unsigned long long ull ;
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;//106110956
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){
if (ch == '-')
f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = (x<<1) + (x<<3) + (ch^48);
ch = getchar();
}
return x * f;
}
void print(__int128 num) {
if(num) {
print(num/10);
putchar(num%10+'0');
}
}
ll ex_gcd(ll a,ll b,ll& x,ll& y){
if(b==0){
x=1;
y=0;
return a;
}
ll d=ex_gcd(b,a%b,y,x);
y=y-a/b*x;
return d;
}
struct Node{
int to,next;
}edge[1000005];
int cnt;
int head[10005];
void add(int u,int v){
cnt++;
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt;
}
int vis[1005][1005];
int in[10005];
int n,m;
int is[10005];
int a[10005];
int ans=1;
int dep[1005];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
memset(is,0,sizeof(is));
memset(a,0,sizeof(a));
int s;
scanf("%d",&s);
for(int j=1;j<=s;j++){
scanf("%d",&a[j]);
is[a[j]]=1;
}
for(int j=a[1];j<=a[s];j++){
if(is[j]==0){
for(int k=1;k<=s;k++){
if(vis[j][a[k]]==0){
vis[j][a[k]]=1;
add(j,a[k]);
in[a[k]]++;
}
}
}
}
}
queue<int>q;
for(int i=1;i<=n;i++){
if(in[i]==0){
q.push(i);
dep[i]=1;
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
dep[v]=dep[u]+1;
ans=max(ans,dep[v]);
in[v]--;
if(in[v]==0){
q.push(v);
}
}
}
printf("%d\n",ans);
return 0;
}