Problem A:水题,直接gan

#include<bits/stdc++.h>
using namespace std;
const int N=305;
int vis[N];
int main()
{
    int p,n;
    cin>>p>>n;
    int flag=-1;
    for(int i=1;i<=n;i++)
    {
        int g;
        scanf("%d",&g);
        int now=g%p;
        if(!vis[now]) vis[now]=1;
        else
        {
            if(flag==-1) flag=i;
        }
    }
    if(flag==-1) puts("-1");
    else printf("%d\n",flag);
    return 0;
}

Problem B:水题,写的时候手贱,<26打成<25 wa了五次!!!!!

Codeforces round FF_i++Codeforces round FF_预处理_02
#include<bits/stdc++.h>
using namespace std;
const int N=2*1e3;
int vis[30];
int k,mx;
char a[N];
int main()
{
    mx=-10000;
    scanf("%s%d",a,&k);
    for(int i=0;i<=25;i++)
    {
        scanf("%d",&vis[i]);
        if(vis[i]>mx) mx=vis[i];
    }
    int ans=0,len=strlen(a);
    for(int i=0;i<len;i++) ans+=(i+1)*vis[a[i]-'a'];
    int cnt=len+1;
    while(k--)
    {
        ans+=cnt*mx;
        cnt++;
    }
    printf("%d\n",ans);
    return 0;
}
View Code

 

Problem C:

题目大意:给你n个数,求连续上升子序列,你将其中一个数该为任意值。

第一个思路:二分答案,看满不满足,可是判断满足的算法是n^2的 不行。
第二个思路:每个断点的前后都是上升序列,枚举这些段。。。这个算法按道理
是可以过的,可是写起来好麻烦啊啊啊啊啊,wawawawawa。
题解:先预处理处每个点的之前上升前缀和之后的上升前缀
枚举没点点当断点
if(a[i+1]-a[i-1]>1)
dp[i]=up[i-1]+down[i+1]+1;
else dp[i]=max(up[i-1],down[i+1])+1;
更新。。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,a[N],up[N],down[N],dp[N];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    up[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(a[i]>a[i-1]) up[i]=up[i-1]+1;
        else up[i]=1;
    }
    down[n]=1;
    for(int i=n-1;i>=1;i--)
    {
        if(a[i]<a[i+1]) down[i]=down[i+1]+1;
        else down[i]=1;
    }
    dp[1]=1+down[2];
    dp[n]=1+up[n-1];
    for(int i=2;i<n;i++)
    {
        if(a[i+1]-a[i-1]>1)
            dp[i]=up[i-1]+down[i+1]+1;
        else dp[i]=max(up[i-1],down[i+1])+1;
    }
    int ans=-1;
    for(int i=1;i<=n;i++) ans=max(ans,dp[i]);
    printf("%d\n",ans);
    return 0;
}

 

Problem D:

题目大意:给你一个n*m的矩阵,给你k个操作,每个操作你可以选其中一行或者其中一列,把他们的和加到ans中,然后这

一行或这一列每个元素减去p,让你求k个操作后ans的最大值。

题解:我们可以这么想,每当我们选取一行(列)时,每一列(行)都减去一个p,这样的话选取之后在列(行)中他们的

相对大小没有变化,所以行和列是完全可以独立开的,如果行数和列数都确定了这个ans值就是确定的和顺序没有关系。

本来我想用两个优先队列存行和列,然后模拟k次,每次取其中的最大值,可是这样是有bug的,正确做法是枚举行数和列数

取其中的最大值。

Codeforces round FF_i++Codeforces round FF_预处理_02
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e3+5;
const int M=1e6+1;
ll n,m,k,p;
ll w[N][N];
ll c[M],r[M];
int main()
{
    scanf("%I64d%I64d%I64d%I64d",&n,&m,&k,&p);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%I64d",&w[i][j]);
    priority_queue<ll> col,row;
    for(int i=1;i<=n;i++)
    {
        ll ans=0;
        for(int j=1;j<=m;j++) ans+=w[i][j];
        col.push(ans);
    }
    for(int j=1;j<=m;j++)
    {
        ll ans=0;
        for(int i=1;i<=n;i++) ans+=w[i][j];
        row.push(ans);
    }
    for(int i=1;i<=k;i++)
    {
        ll now=col.top();col.pop();
        c[i]=c[i-1]+now;
        col.push(now-m*p);
    }
    for(int i=1;i<=k;i++)
    {
        ll now=row.top();row.pop();
        r[i]=r[i-1]+now;
        row.push(now-n*p);
    }
    ll ans=c[0]+r[k];
    for(ll i=1;i<=k;i++)
    {
        if((c[i]+r[k-i]-i*(k-i)*p)>ans) ans=c[i]+r[k-i]-i*(k-i)*p;
    }
    printf("%I64d\n",ans);
    return 0;
}
View Code