Bobo String Construction 结论,字符串哈希
Election of the King 二分查找
Merge the squares! 递归模拟,辗转相除法
Qu'est-ce Que C'est? DP,前缀和优化
We are the Lights 思维,倒推
猜测是,把n个字符全填0或者1是最优的。所以只需要字符串哈希检查是否两个串里面含有给定串即可。
#include <bits/stdc++.h>using namespace std;
typedef long long int ll;
# define p1 13331
# define p2 1331
# define mod1 998244353
# define mod2 1000000007
ll base1[5000+10],base2[5000+10],sum1[5000+10],sum2[5000+10],ans1,ans2;
int n,m;
ll getsum1(int l,int r)
{ll ans=((sum1[r]-(sum1[l-1]*base1[r-l+1]%mod1)%mod1)%mod1+mod1)%mod1;return ans;
}
ll getsum2(int l,int r)
{ll ans=((sum2[r]-(sum2[l-1]*base2[r-l+1]%mod2)%mod2)%mod2+mod2)%mod2;return ans;
}
int main()
{int t;cin>>t;base1[0]=base2[0]=1;for(int i=1; i<=5000; i++){base1[i]=p1*base1[i-1]%mod1;base2[i]=p2*base2[i-1]%mod2;}while(t--){cin>>n;string s;cin>>s;string pres=s;m=s.length();s=" "+s;ans1=0,ans2=0;for(int i=1; i<=m; i++){ans1=(ans1*p1%mod1+(int)(s[i]-'0'))%mod1;ans2=(ans2*p2%mod2+(int)(s[i]-'0'))%mod2;}string temp1=s;for(int i=1; i<=n; i++){temp1+='1';}temp1+=pres;string temp2=s;for(int i=1; i<=n; i++){temp2+='0';}temp2+=pres;int len1=pres.length()*2+n,len2=len1;for(int i=1; i<=len1; i++){sum1[i]=(sum1[i-1]*p1%mod1+(int)(temp1[i]-'0'))%mod1;sum2[i]=(sum2[i-1]*p2%mod2+(int)(temp1[i]-'0'))%mod2;}int flag=0;for(int i=2; i+m-1<len1; i++){ll now1=getsum1(i,i+m-1);ll now2=getsum2(i,i+m-1);if(now1==ans1&&now2==ans2){flag=1;break;}}if(flag==0){for(int i=1; i<=n; i++){cout<<1;}cout<<'\n';continue;}temp1=temp2;for(int i=1; i<=len1; i++){sum1[i]=(sum1[i-1]*p1%mod1+(int)(temp1[i]-'0'))%mod1;sum2[i]=(sum2[i-1]*p2%mod2+(int)(temp1[i]-'0'))%mod2;}flag=0;for(int i=2; i+m-1<len1; i++){ll now1=getsum1(i,i+m-1);ll now2=getsum2(i,i+m-1);if(now1==ans1&&now2==ans2){flag=1;break;}}if(flag==0){for(int i=1; i<=n; i++){cout<<0;}cout<<'\n';continue;}cout<<-1<<'\n';}return 0;
}
首先,对数组进行排序。以1 2 3 4 5为例,>=3的全部都投向5,否则都投给1。我们只需要获得当前[L,R]区间的(A[L]+A[R]) /2,如果(A[L]+A[R])恰好整除2,则全部大于等于这个值的都投给右侧,如果不能整除2,即为某.5,同样全部大于这个值的都投给右侧,故采用upper_bound,再pos--,即获得投给左侧的全部。
# include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
struct node
{int id,val;friend bool operator<(node x, node y){return x.val<y.val;}
};
struct node s[1000000+10];bool cmp(struct node x, struct node y)
{return x.val<y.val;
}
int main ()
{int n;cin>>n;for(int i=1;i<=n;i++){scanf("%d",&s[i].val);s[i].id=i;}sort(s+1,s+1+n,cmp);int l=1,r=n;for(int i=1;i<=n-1;i++){int now=(s[l].val+s[r].val)/2;struct node temp;temp.id=0;temp.val=now;int mid=upper_bound(s+l,s+1+r,temp)-s;mid--;int flag=0;if(s[mid].val==now)flag++;if(mid-l+1>=r-mid){r--;}else{l++;}}cout<<s[l].id;return 0;
}
首先,当n包含某个因子的时候,如果这一因子小于等于7,大于1,就可以合并每个因子*因子的正方形。但当n为质数的时候,这一方法失效。故考虑构造正方形n*n为四部分,
n*n=(a+b)*(a+b)。对于黄色长方形,按照辗转相处法构造,即每次以较短边为边长构造正方形。对于蓝色正方形,我们继续按照这一规则,递归构造。而当前n选择的a,b值,可以暴力枚举n的a值,检验这个a*b的长方形构造出的正方形个数是否满足2*cnt+2<=50.即我们假定蓝色已经递归构造成功。值得注意的是,因为任意正方形一定是n*n的平方数,故我们一定可以找到a,b。而对于是否有界,并不会做充分证明。
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
int ans[1010],n;
bool check(int x,int y)
{if(y==0){return x<=7;}int cnt=0;int a=x,b=y,c;while(b){cnt+=a/b;c=a;a=b;b=c%b;}return cnt*2+2<=50;
}
struct node
{int x,y,len;
};
stack<node>temp;
void dfs(int,int,int);
void workC(int,int,int,int);
void workR(int x,int y,int row,int col) //行短
{if(row==1)return ;int cnt=col/row;for(int i=1;i<=cnt;i++){dfs(x,y+(i-1)*row,row);}int yu=col%row;if(yu){workC(x,y+(cnt)*row,row,yu);}
}
void workC(int x,int y,int row,int col)
{if(col==1)return ;int cnt=row/col;for(int i=1;i<=cnt;i++){dfs(x+(i-1)*col,y,col);}int yu=row%col;if(yu){workR(x+cnt*col,y,yu,col);}
}
void dfs(int x,int y,int len)
{if(len==1)return;struct node now;now.len=len;now.x=x;now.y=y;temp.push(now);if(ans[len]==0)return ;int a=len-ans[len],b=ans[len];workR(x+a,y,b,a);workC(x,y+a,a,b);dfs(x,y,a);dfs(x+a,y+a,b);return ;
}
int main()
{cin>>n;for(int i=1;i<=n;i++){ans[i]=-1;for(int j=0;j<=i/2;j++){if(check(i-j,j)){ans[i]=j;// break;}}}dfs(1,1,n);cout<<temp.size()<<'\n';while(!temp.empty()){struct node now=temp.top();temp.pop();cout<<now.x<<" "<<now.y<<" "<<now.len<<'\n';}return 0;
}
首先如果仅看两两之和大于等于0是很难转移的。不妨强制两种块,一种是一个正数,一种是一个负数和一个正数。这样可以获得类似于 负正正正负正正 的局面。而至于为什么不是正负组合,主要是因为,负数在前面放置,可以满足前面块和负数之和不为负数,也方便存储。缺点是,不能包含最后一个是负数的情况,故需要特判,由dp[n-1][i]*i转移。
写出暴力n^3的DP后,可以发现是可以进行前缀和优化的,且需要两个前缀和。第二个前缀和的推导,可以借助暴力程序的画图,找出枚举规律。可见,特殊的dp枚举优化,可以通过画图直观解决。
# include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
# define mod 998244353
ll dp[5010][5010];
int sum[5010][5010];
ll sumji[5010][5010];
int main()
{int n;ll m;cin>>n>>m;if(n==1){cout<<m+m+1;return 0;}dp[0][0]=1;for(int i=0; i<=m; i++){sum[0][i]=1;}for(int i=0; i<=m; i++){dp[1][i]=1;sum[1][i]=i+1;if(i){sumji[1][i]=(dp[1][i]*(ll)i)%mod;sumji[1][i]=(sumji[1][i-1]+sumji[1][i])%mod;}}for(int i=0; i<=m; i++){for(int j=0; j<=m; j++){dp[2][i]=(dp[2][i]+dp[1][j])%mod;}for(int k=-m; k<=-1; k++){int zheng=i-k;if(zheng<=m&&zheng>=0){dp[2][i]=(dp[2][i]+1)%mod;}}sumji[2][i]=(dp[2][i]*(ll)i)%mod;sum[2][i]=dp[2][i];if(i){sum[2][i]+=sum[2][i-1];sum[2][i]%=mod;sumji[2][i]=(sumji[2][i]+sumji[2][i-1])%mod;}}for(int i=3; i<=n; i++){for(int j=0; j<=m; j++){dp[i][j]=(dp[i][j]+sum[i-1][m])%mod;ll temp=((sum[i-2][m]-sum[i-2][m-j])%mod+mod)%mod;dp[i][j]=(((dp[i][j]+sumji[i-2][m-j])%mod+(ll)(m-j)*temp%mod)%mod)%mod;sumji[i][j]=dp[i][j]*(ll)(j)%mod;sum[i][j]=dp[i][j];if(j){sumji[i][j]=(sumji[i][j]+sumji[i][j-1])%mod;sum[i][j]=(sum[i][j]+sum[i][j-1])%mod;}}}ll ans=0;ans+=sum[n][m];ans%=mod;ans+=sumji[n-1][m];ans%=mod;cout<<ans;return 0;
}
倒着推,但凡倒着推先点亮的,必定点亮,反之已然。然后就可以画图解决去重问题,利用点亮行的数量,关闭行的数量,点亮和关闭列的数量即可。
# include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
int bookhang[1000000+10],booklie[1000000+10],n,m;
struct node
{int flag,id,on;
};
struct node s[1000000+10];
int main()
{cin.tie(0);ios::sync_with_stdio(0);int n,m;cin>>n>>m;int t;cin>>t;for(int i=1;i<=n;i++){bookhang[i]=-1;}for(int i=1;i<=m;i++){booklie[i]=-1;}for(int i=1;i<=t;i++){string ch;cin>>ch;int id;string on;cin>>id>>on;if(ch[0]=='r'){s[i].flag=1;}else{s[i].flag=0;}s[i].id=id;if(on[1]=='n'){s[i].on=1;}else{s[i].on=0;}}ll ans=0;ll lianghang=0,guanhang=0,lianglie=0,guanlie=0;for(int i=t;i>=1;i--){if(s[i].flag==1){if(s[i].on==1){if(bookhang[s[i].id]==-1){ans+=(m-lianglie-guanlie);bookhang[s[i].id]=1;lianghang++;}}else{if(bookhang[s[i].id]==-1){bookhang[s[i].id]=1;guanhang++;}}}else{if(s[i].on==1){if(booklie[s[i].id]==-1){ans+=(n-lianghang-guanhang);booklie[s[i].id]=1;lianglie++;}}else{if(booklie[s[i].id]==-1){booklie[s[i].id]=1;guanlie++;}}}}cout<<ans;return 0;
}