noip11

T1

考试的时候打的暴力,快结束的时候,脑抽加了个 long long,然后就...

image

痛失70pts QAQ。

Your source code compiled to 8015900 bytes which is too big, too thick, too long for us..
#include<cstdio>
#include<algorithm>
#define MAX 1000001
#define re register
#define int long long
namespace OMA
{
   int n,k,cnt;
   int ans[MAX],b[MAX]={1};
   inline int read()
   {
     int s=0,w=1; char ch=getchar();
     while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
     while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
     return s*w;
   }
   signed main()
   {
     n = read(),k = read();
     ans[++cnt] = 0;
     for(re int i=1; i<=n; i++)
     {
       int a = read();
       for(re int j=1; j<=k; j++)
       {
         int tmp = a*j%k;
         if(!b[tmp])
         { ans[++cnt] = tmp; b[tmp] = 1; }
       }
     }
     std::sort(ans+1,ans+1+cnt);
     printf("%lld\n",cnt);
     for(re int i=1; i<=cnt; i++)
     { printf("%lld ",ans[i]); }
     return 0;
   }
}
signed main()
{ return OMA::main(); }

又大又厚又长

其实跟正解就差一个gcd了,其他基本就都一样,就gcd,害。

然后我考试的时候,还想着去找循环节,后来发现没啥用,就扔了个暴力走了。

正解:

\(ax+by=z\) 有解的充要条件是 \(gcd(a,b)|z\),所以求 \(gcd(a_{1},a_{2},....a_{n})\) ,然后直接枚举其模 \(k\) 意义下的倍数,统计答案即可。

求倍数的时候可能会暴int ,或者出现负数,注意一下。

然后,xin写的模拟退火,经它观察,答案为等比序列,所以去找公差,找到什么时候呢?,0.85s的时候就差不多了,然后就统计答案,大概率是对的目前卡不掉

Code
#include<cstdio>
#include<algorithm>
#define MAX 1000010
#define re register
namespace OMA
{
   int n,k,cnt;
   int ans[MAX],b[MAX]={1};
   inline int read()
   {
     int s=0,w=1; char ch=getchar();
     while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
     while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
     return s*w;
   }
   inline int gcd(int a,int b)
   { return b?gcd(b,a%b):a; }
   signed main()
   {
     n = read(),k = read();
     int p = 0;
     ans[++cnt] = 0;
     for(re int i=1; i<=n; i++)
     { p = gcd(read(),p); }
     for(re int i=1; i<=k-1; i++)
     { int tmp = (1LL*p*i%k+k)%k; if(!b[tmp]){ ans[++cnt] = tmp; b[tmp] = 1; }; }
     std::sort(ans+1,ans+1+cnt);
     printf("%d\n",cnt);
     for(re int i=1; i<=cnt; i++)
     { printf("%d ",ans[i]); }
     return 0;
   }
}
signed main()
{ return OMA::main(); }

T2

考试的时候,想的按 \(a\) 来排序,然后直接dp,然而它是二维的,不能直接sort,就去想怎么压到一维,觉得有些麻烦,结果两行了事,记一下x,y就好,此时t3还没看,就去写t3了。

首先dp方程,设 \(dp_{i,j}\) 表示到i,j时最大的吸引度之和,则有,

\[dp_{i,j}=\max(dp_{i',j'}+b_{i,j}+\left\vert i-i' \right\vert+\left\vert j-j' \right\vert) \]

40pts,直接暴力转移。
80pts,考虑优化,方程中有abs,套路的想到将其拆成,

\[dp_{i,j}+i+j \]

\[dp_{i,j}+i-j \]

\[dp_{i,j}-i+j \]

\[dp_{i,j}-i-j \]

即从左上,左下,右上,右下四个地方转移过来跟上边的式子顺序可能对不上,然后就可以用树状数组来维护其最大值,今天才知道的套路

100pts,其实用不着树状数组,坐标的差如果为负数的话,肯定不是最优的,所以直接用四个变量来维护即可。

dp方程没必要是二维的,可以直接统计个数,搞成一维的。
记得开long long

Code
#include<cstdio>
#include<algorithm>
#define MAX 2001
#define re register
#define int long long
namespace OMA
{
   int n,m;
   int tmp[4][2];
   int dp[MAX*MAX],ans;
   struct node
   {
     int a,b;
     int x,y;
     friend bool operator <(const node &a,const node &b)
     { return a.a<b.a;; }
   }ar[MAX*MAX];
   int a[MAX][MAX],b[MAX][MAX];
   inline int read()
   { 
     int s=0,w=1; char ch=getchar();
     while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
     while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
     return s*w;
   }
   inline int max(int a,int b)
   { return a>b?a:b; }
   inline void work(int i)
   {
     tmp[0][0] = max(tmp[0][0],dp[i]+ar[i].x+ar[i].y);
     tmp[1][0] = max(tmp[1][0],dp[i]+ar[i].x-ar[i].y);
     tmp[2][0] = max(tmp[2][0],dp[i]-ar[i].x+ar[i].y);
     tmp[3][0] = max(tmp[3][0],dp[i]-ar[i].x-ar[i].y);
   }
   signed main()
   {
     int cnt = 0,head;
     n = read(),m = read();
     for(re int i=1; i<=n; i++)
     {
       for(re int j=1; j<=m; j++)
       { a[i][j] = read(); }
     }
     for(re int i=1; i<=n; i++)
     {
       for(re int j=1; j<=m; j++)
       {
         b[i][j] = read();
         if(a[i][j])
         { ar[++cnt] = (node){a[i][j],b[i][j],i,j}; }
       }
     }
     std::sort(ar+1,ar+1+cnt);
     dp[1] = ar[1].b,work(1);
     for(re int i=2; i<=cnt; i++)
     {
       if(ar[i].a!=ar[i-1].a)
       { head = i; break ; }
       dp[i] = ar[i].b,work(i);
     }
     for(re int i=head; i<=cnt; i++)
     {
       if(ar[i].a!=ar[i-1].a)
       {
         for(re int j=0; j<=3; j++)
         { tmp[j][1] = tmp[j][0],tmp[j][0] = 0; }
       }
       int a = tmp[0][1]-ar[i].x-ar[i].y;
       int b = tmp[1][1]-ar[i].x+ar[i].y;
       int c = tmp[2][1]+ar[i].x-ar[i].y;
       int d = tmp[3][1]+ar[i].x+ar[i].y;
       ans = max(ans,dp[i] = max(max(a,b),max(c,d))+ar[i].b); 
       work(i);
     }
     printf("%lld\n",ans);
     return 0;
   }
}
signed main()
{ return OMA::main(); }

T3

跳过t2后,看的t3,暴力很好打,很快就码好了,20pts到手,去看测试点特征,对于仅有0,1的点,opt=1,答案即为0,1个数之积,opt=2显然答案为0,+=20pts,数错数了,20挂掉了

暴力找最大值显然不可行,所以想到了单调队列单调栈,然而写挂了,去想别的方法去优化,然后莫名其妙的想到了树套树区间最大值,显然树套树,学fhq-treap学傻了,还没码完,考试结束了。

正解是可持久化Trie。还不会,所以去学了。
没改出来,先咕了

posted @ 2021-07-11 18:59  -OMA-  阅读(121)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end